diff options
651 files changed, 9942 insertions, 2749 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index c30164c065af..864caf4da9fd 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -42,6 +42,7 @@ aconfig_srcjars = [ ":android.credentials.flags-aconfig-java{.generated_srcjars}", ":android.view.contentprotection.flags-aconfig-java{.generated_srcjars}", ":android.service.voice.flags-aconfig-java{.generated_srcjars}", + ":android.service.autofill.flags-aconfig-java{.generated_srcjars}", ] filegroup { @@ -242,6 +243,11 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +cc_aconfig_library { + name: "aconfig_view_flags_c_lib", + aconfig_declarations: "android.view.flags-aconfig", +} + // View.accessibility aconfig_declarations { name: "android.view.accessibility.flags-aconfig", @@ -416,3 +422,19 @@ java_aconfig_library { aconfig_declarations: "android.service.voice.flags-aconfig", defaults: ["framework-minus-apex-aconfig-java-defaults"], } + +// Autofill +aconfig_declarations { + name: "android.service.autofill.flags-aconfig", + package: "android.service.autofill", + srcs: [ + "services/autofill/bugfixes.aconfig", + "services/autofill/features.aconfig" + ], +} + +java_aconfig_library { + name: "android.service.autofill.flags-aconfig-java", + aconfig_declarations: "android.service.autofill.flags-aconfig", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java index 43d2ae9e077b..f47766ed0393 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -1335,13 +1335,13 @@ public final class JobServiceContext implements ServiceConnection { private void handleOpTimeoutLocked() { switch (mVerb) { case VERB_BINDING: - onSlowAppResponseLocked(/* reschedule */ false, /* updateStopReasons */ true, + // The system may have been too busy. Don't drop the job or trigger an ANR. + onSlowAppResponseLocked(/* reschedule */ true, /* updateStopReasons */ true, /* texCounterMetricId */ "job_scheduler.value_cntr_w_uid_slow_app_response_binding", /* debugReason */ "timed out while binding", /* anrMessage */ "Timed out while trying to bind", - CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES, - mRunningJob.getUid())); + /* triggerAnr */ false); break; case VERB_STARTING: // Client unresponsive - wedged or failed to respond in time. We don't really diff --git a/api/Android.bp b/api/Android.bp index 45e70719e6c0..222275f9a4e4 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -82,7 +82,6 @@ combined_apis { "framework-media", "framework-mediaprovider", "framework-ondevicepersonalization", - "framework-pdf", "framework-permission", "framework-permission-s", "framework-scheduling", diff --git a/api/javadoc-lint-baseline b/api/javadoc-lint-baseline index 871312640acf..2cc5078c8844 100644 --- a/api/javadoc-lint-baseline +++ b/api/javadoc-lint-baseline @@ -8,9 +8,12 @@ android/adservices/ondevicepersonalization/ExecuteOutput.java:20: lint: Unresolv android/adservices/ondevicepersonalization/ExecuteOutput.java:31: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onExecute() IsolatedWorker#onExecute()" in android.adservices.ondevicepersonalization.ExecuteOutput [101] android/adservices/ondevicepersonalization/ExecuteOutput.java:93: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onExecute() IsolatedWorker#onExecute()" in android.adservices.ondevicepersonalization.ExecuteOutput.Builder [101] android/adservices/ondevicepersonalization/IsolatedService.java:18: lint: Unresolved link/see tag "SurfaceView" in android.adservices.ondevicepersonalization.IsolatedService [101] +android/adservices/ondevicepersonalization/IsolatedService.java:18: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.OnDevicePersonalizationManager#execute" in android.adservices.ondevicepersonalization.IsolatedService [101] android/adservices/ondevicepersonalization/IsolatedService.java:119: lint: Unresolved link/see tag "IsolatedCmputationCallback#onWebViewEvent()" in android.adservices.ondevicepersonalization.IsolatedService [101] +android/adservices/ondevicepersonalization/IsolatedService.java:119: lint: Unresolved link/see tag "IsolatedCmputationCallback#onEvent()" in android.adservices.ondevicepersonalization.IsolatedService [101] android/adservices/ondevicepersonalization/IsolatedService.java:119: lint: Unresolved link/see tag "WebView" in android.adservices.ondevicepersonalization.IsolatedService [101] android/adservices/ondevicepersonalization/IsolatedWorker.java:9: lint: Unresolved link/see tag "RunTimeException" in android.adservices.ondevicepersonalization.IsolatedWorker [101] +android/adservices/ondevicepersonalization/IsolatedWorker.java:24: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.OnDevicePersonalizationManager#execute" in android.adservices.ondevicepersonalization.IsolatedWorker [101] android/adservices/ondevicepersonalization/IsolatedWorker.java:57: lint: Unresolved link/see tag "#onExecute()" in android.adservices.ondevicepersonalization.IsolatedWorker [101] android/adservices/ondevicepersonalization/IsolatedWorker.java:74: lint: Unresolved link/see tag "#onRender()" in android.adservices.ondevicepersonalization.IsolatedWorker [101] android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:-11: lint: Unresolved link/see tag "requestSurfacePackage" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101] @@ -226,40 +229,6 @@ android/service/notification/NotificationListenerService.java:1155: lint: Unreso android/service/notification/NotificationListenerService.java:1166: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService NotificationAssistantService" in android.service.notification.NotificationListenerService.Ranking [101] android/service/quickaccesswallet/WalletCard.java:285: lint: Unresolved link/see tag "PackageManager.FEATURE_WALLET_LOCATION_BASED_SUGGESTIONS" in android.service.quickaccesswallet.WalletCard.Builder [101] android/service/voice/VoiceInteractionSession.java:293: lint: Unresolved link/see tag "android.service.voice.VoiceInteractionService#KEY_SHOW_SESSION_ID VoiceInteractionService#KEY_SHOW_SESSION_ID" in android.service.voice.VoiceInteractionSession [101] -android/telecom/Call.java:94: lint: unable to parse link/see tag: #playDtmfTone(char [101] -android/telecom/CallControl.java:163: lint: Unresolved link/see tag "android.telecom.CallStreamingService CallStreamingService" in android.telecom.CallControl [101] -android/telecom/CallControlCallback.java:63: lint: Unresolved link/see tag "android.telecom.CallAttributes.CallType" in android.telecom.CallControlCallback [101] -android/telecom/PhoneAccountSuggestion.java:17: lint: Unresolved link/see tag "android.telecom.PhoneAccountSuggestionService PhoneAccountSuggestionService" in android.telecom.PhoneAccountSuggestion [101] -android/telephony/CarrierConfigManager.java:2934: lint: Unresolved link/see tag "android.telephony.TelephonyManager.PremiumCapability TelephonyManager.PremiumCapability" in android.telephony.CarrierConfigManager [101] -android/telephony/CarrierConfigManager.java:4020: lint: Unresolved link/see tag "ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.CarrierConfigManager.Ims [101] -android/telephony/CarrierConfigManager.java:4108: lint: Unresolved link/see tag "ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.CarrierConfigManager.Ims [101] -android/telephony/CarrierConfigManager.java:3920: lint: Unresolved link/see tag "android.telephony.ims.SipDelegateManager" in android.telephony.CarrierConfigManager.Ims [101] -android/telephony/CarrierConfigManager.java:4001: lint: Unresolved link/see tag "ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.CarrierConfigManager.Ims [101] -android/telephony/CarrierConfigManager.java:4089: lint: Unresolved link/see tag "ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.CarrierConfigManager.Ims [101] -android/telephony/NetworkRegistrationInfo.java:131: lint: Unresolved link/see tag "android.telephony.Annotation.NetworkType NetworkType" in android.telephony.NetworkRegistrationInfo [101] -android/telephony/PhoneStateListener.java:293: lint: Unresolved link/see tag "android.telephony.PreciseDisconnectCause PreciseDisconnectCause" in android.telephony.PhoneStateListener [101] -android/telephony/PhoneStateListener.java:544: lint: Unresolved link/see tag "android.telephony.PreciseDisconnectCause PreciseDisconnectCause" in android.telephony.PhoneStateListener [101] -android/telephony/SubscriptionManager.java:1385: lint: Unresolved link/see tag "Build.VERSION_CODES.P" in android.telephony.SubscriptionManager.OnSubscriptionsChangedListener [101] -android/telephony/SubscriptionManager.java:1385: lint: Unresolved link/see tag "Build.VERSION_CODES.V" in android.telephony.SubscriptionManager.OnSubscriptionsChangedListener [101] -android/telephony/SubscriptionPlan.java:134: lint: Unresolved link/see tag "android.telephony.Annotation.NetworkType NetworkType" in android.telephony.SubscriptionPlan [101] -android/telephony/SubscriptionPlan.java:288: lint: Unresolved link/see tag "android.telephony.Annotation.NetworkType NetworkType" in android.telephony.SubscriptionPlan.Builder [101] -android/telephony/TelephonyCallback.java:113: lint: Unresolved link/see tag "android.telephony.PreciseDisconnectCause PreciseDisconnectCause" in android.telephony.TelephonyCallback.CallDisconnectCauseListener [101] -android/telephony/TelephonyManager.java:2544: lint: Unresolved link/see tag "android.telephony.TelephonyManager.CarrierRestrictionStatus CarrierRestrictionStatus" in android.telephony.TelephonyManager [101] -android/telephony/TelephonyManager.java:2841: lint: Unresolved link/see tag "android.telephony.TelephonyManager.SetOpportunisticSubscriptionResult TelephonyManager.SetOpportunisticSubscriptionResult" in android.telephony.TelephonyManager [101] -android/telephony/TelephonyManager.java:3273: lint: Unresolved link/see tag "android.telephony.TelephonyManager.PurchasePremiumCapabilityResult PurchasePremiumCapabilityResult" in android.telephony.TelephonyManager [101] -android/telephony/TelephonyManager.java:3989: lint: Unresolved link/see tag "android.telephony.TelephonyManager.MobileDataPolicy MobileDataPolicy" in android.telephony.TelephonyManager [101] -android/telephony/data/ApnSetting.java:39: lint: Unresolved link/see tag "android.telephony.data.DataCallResponse#getMtuV4() DataCallResponse#getMtuV4()" in android.telephony.data.ApnSetting [101] -android/telephony/data/ApnSetting.java:50: lint: Unresolved link/see tag "android.telephony.data.DataCallResponse#getMtuV6() DataCallResponse#getMtuV6()" in android.telephony.data.ApnSetting [101] -android/telephony/data/ApnSetting.java:597: lint: Unresolved link/see tag "android.telephony.data.DataCallResponse#getMtuV4() DataCallResponse#getMtuV4()" in android.telephony.data.ApnSetting.Builder [101] -android/telephony/data/ApnSetting.java:611: lint: Unresolved link/see tag "android.telephony.data.DataCallResponse#getMtuV6() DataCallResponse#getMtuV6()" in android.telephony.data.ApnSetting.Builder [101] -android/telephony/euicc/EuiccManager.java:331: lint: Unresolved link/see tag "android.service.euicc.EuiccService#ACTION_BIND_CARRIER_PROVISIONING_SERVICE" in android.telephony.euicc.EuiccManager [101] -android/telephony/ims/ImsMmTelManager.java:117: lint: Unresolved link/see tag "android.telephony.ims.ImsService ImsService" in android.telephony.ims.ImsMmTelManager [101] -android/telephony/ims/ImsRcsManager.java:43: lint: Unresolved link/see tag "android.telephony.ims.ImsService ImsService" in android.telephony.ims.ImsRcsManager [101] -android/telephony/ims/ProvisioningManager.java:102: lint: Unresolved link/see tag "android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability MmTelFeature.MmTelCapabilities.MmTelCapability" in android.telephony.ims.ProvisioningManager [101] -android/telephony/ims/ProvisioningManager.java:102: lint: Unresolved link/see tag "android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.ims.ProvisioningManager [101] -android/telephony/ims/ProvisioningManager.java:136: lint: Unresolved link/see tag "android.telephony.ims.ImsRcsManager.RcsImsCapabilityFlag ImsRcsManager.RcsImsCapabilityFlag" in android.telephony.ims.ProvisioningManager [101] -android/telephony/ims/RegistrationManager.java:21: lint: Unresolved link/see tag "android.telephony.ims.feature.ImsFeature ImsFeature" in android.telephony.ims.RegistrationManager [101] -android/telephony/ims/RegistrationManager.java:24: lint: Unresolved link/see tag "android.telephony.ims.ImsService ImsService" in android.telephony.ims.RegistrationManager [101] android/text/DynamicLayout.java:141: lint: Unresolved link/see tag "LineBreakconfig" in android.text.DynamicLayout [101] android/text/WordSegmentFinder.java:13: lint: Unresolved link/see tag "android.text.method.WordIterator WordIterator" in android.text.WordSegmentFinder [101] android/view/InputDevice.java:71: lint: Unresolved link/see tag "InputManagerGlobal.InputDeviceListener" in android.view.InputDevice [101] @@ -291,76 +260,6 @@ android/view/inputmethod/InputMethodManager.java:456: lint: Unresolved link/see android/view/inspector/PropertyReader.java:141: lint: Unresolved link/see tag "android.annotation.ColorInt ColorInt" in android.view.inspector.PropertyReader [101] android/window/BackEvent.java:24: lint: Unresolved link/see tag "android.window.BackMotionEvent BackMotionEvent" in android.window.BackEvent [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_30" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_35" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_40" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_45" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_50" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_55" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_60" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_65" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_70" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_75" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_80" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_85" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_90" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_30" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_35" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_40" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_45" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_50" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_55" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_60" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_65" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_70" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_75" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_80" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_85" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_90" in android [101] -com/android/server/wm/CompatModePackages.java:135: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:135: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:135: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_90" in android [101] -com/android/server/wm/CompatModePackages.java:148: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:148: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:148: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_85" in android [101] -com/android/server/wm/CompatModePackages.java:161: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:161: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:161: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_80" in android [101] -com/android/server/wm/CompatModePackages.java:174: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:174: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:174: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_75" in android [101] -com/android/server/wm/CompatModePackages.java:187: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:187: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:187: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_70" in android [101] -com/android/server/wm/CompatModePackages.java:200: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:200: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:200: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_65" in android [101] -com/android/server/wm/CompatModePackages.java:213: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:213: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:213: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_60" in android [101] -com/android/server/wm/CompatModePackages.java:226: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:226: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:226: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_55" in android [101] -com/android/server/wm/CompatModePackages.java:239: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:239: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:239: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_50" in android [101] -com/android/server/wm/CompatModePackages.java:252: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:252: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:252: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_45" in android [101] -com/android/server/wm/CompatModePackages.java:265: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:265: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:265: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_40" in android [101] -com/android/server/wm/CompatModePackages.java:278: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:278: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:278: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_35" in android [101] -com/android/server/wm/CompatModePackages.java:291: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:291: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:291: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_30" in android [101] - android/net/wifi/SoftApConfiguration.java:173: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)" in android.net.wifi.SoftApConfiguration [101] android/content/pm/ActivityInfo.java:1197: lint: Unresolved link/see tag "android.view.ViewRootImpl" in android.content.pm.ActivityInfo [101] android/os/UserManager.java:2384: lint: Unresolved link/see tag "android.annotation.UserHandleAware @UserHandleAware" in android.os.UserManager [101] @@ -370,7 +269,6 @@ android/service/voice/AlwaysOnHotwordDetector.java:269: lint: Unresolved link/se android/service/voice/AlwaysOnHotwordDetector.java:278: lint: Unresolved link/see tag "#STATE_ERROR" in android [101] android/service/voice/AlwaysOnHotwordDetector.java:278: lint: Unresolved link/see tag "Callback#onFailure" in android [101] android/service/voice/AlwaysOnHotwordDetector.java:278: lint: Unresolved link/see tag "Callback#onUnknownFailure" in android [101] -android/telephony/TelephonyRegistryManager.java:242: lint: Unresolved link/see tag "#listenFromListener" in android [101] android/view/animation/AnimationUtils.java:64: lint: Unresolved link/see tag "Build.VERSION_CODES#VANILLA_ICE_CREAM" in android.view.animation.AnimationUtils [101] android/view/contentcapture/ContentCaptureSession.java:188: lint: Unresolved link/see tag "UPSIDE_DOWN_CAKE" in android.view.contentcapture.ContentCaptureSession [101] com/android/internal/policy/PhoneWindow.java:172: lint: Unresolved link/see tag "Build.VERSION_CODES#VANILLA_ICE_CREAM" in com.android.internal.policy.PhoneWindow [101] @@ -393,7 +291,6 @@ com/android/server/pm/PackageInstallerSession.java:327: lint: Unresolved link/se com/android/server/pm/PackageInstallerSession.java:327: lint: Unresolved link/see tag "PackageInstaller.SessionParams#setRequestUpdateOwnership(boolean)" in android [101] com/android/server/pm/PackageInstallerSession.java:358: lint: Unresolved link/see tag "IntentSender" in android [101] com/android/server/devicepolicy/DevicePolicyManagerService.java:860: lint: Unresolved link/see tag "android.security.IKeyChainService#setGrant" in android [101] -android/telephony/SubscriptionManager.java:1370: lint: Unresolved link/see tag "Build.VERSION_CODES.Q" in android.telephony.SubscriptionManager.OnSubscriptionsChangedListener [101] android/companion/virtual/sensor/VirtualSensorDirectChannelWriter.java:-4: lint: Invalid tag: @Override [131] android/companion/virtual/sensor/VirtualSensorDirectChannelWriter.java:-1: lint: Invalid tag: @Override [131] diff --git a/core/api/current.txt b/core/api/current.txt index d037c31e5af7..5a1561ad80da 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -10992,6 +10992,7 @@ package android.content { field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED"; field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED"; field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED"; + field @FlaggedApi("android.content.pm.stay_stopped") public static final String ACTION_PACKAGE_UNSTOPPED = "android.intent.action.PACKAGE_UNSTOPPED"; field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED"; field public static final String ACTION_PASTE = "android.intent.action.PASTE"; field public static final String ACTION_PICK = "android.intent.action.PICK"; @@ -12673,6 +12674,7 @@ package android.content.pm { method public boolean isDeviceUpgrading(); method public abstract boolean isInstantApp(); method public abstract boolean isInstantApp(@NonNull String); + method @FlaggedApi("android.content.pm.stay_stopped") public boolean isPackageStopped(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException; method public boolean isPackageSuspended(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException; method public boolean isPackageSuspended(); method @CheckResult public abstract boolean isPermissionRevokedByPolicy(@NonNull String, @NonNull String); @@ -17666,6 +17668,7 @@ package android.graphics.text { field public static final int LINE_BREAK_STYLE_LOOSE = 1; // 0x1 field public static final int LINE_BREAK_STYLE_NONE = 0; // 0x0 field public static final int LINE_BREAK_STYLE_NORMAL = 2; // 0x2 + field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int LINE_BREAK_STYLE_NO_BREAK = 4; // 0x4 field public static final int LINE_BREAK_STYLE_STRICT = 3; // 0x3 field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int LINE_BREAK_STYLE_UNSPECIFIED = -1; // 0xffffffff field public static final int LINE_BREAK_WORD_STYLE_NONE = 0; // 0x0 @@ -46672,10 +46675,10 @@ package android.text { method @NonNull public android.text.DynamicLayout.Builder setHyphenationFrequency(int); method @NonNull public android.text.DynamicLayout.Builder setIncludePad(boolean); method @NonNull public android.text.DynamicLayout.Builder setJustificationMode(int); - method @NonNull public android.text.DynamicLayout.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig); + method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.text.DynamicLayout.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig); method @NonNull public android.text.DynamicLayout.Builder setLineSpacing(float, @FloatRange(from=0.0) float); method @NonNull public android.text.DynamicLayout.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic); - method @NonNull public android.text.DynamicLayout.Builder setUseBoundsForWidth(boolean); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.DynamicLayout.Builder setUseBoundsForWidth(boolean); method @NonNull public android.text.DynamicLayout.Builder setUseLineSpacingFromFallbacks(boolean); } @@ -47199,7 +47202,7 @@ package android.text { method @NonNull public android.text.StaticLayout.Builder setMaxLines(@IntRange(from=0) int); method public android.text.StaticLayout.Builder setText(CharSequence); method @NonNull public android.text.StaticLayout.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic); - method @NonNull public android.text.StaticLayout.Builder setUseBoundsForWidth(boolean); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.StaticLayout.Builder setUseBoundsForWidth(boolean); method @NonNull public android.text.StaticLayout.Builder setUseLineSpacingFromFallbacks(boolean); } @@ -47912,6 +47915,10 @@ package android.text.style { method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig(); } + @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final class LineBreakConfigSpan.NoBreakSpan extends android.text.style.LineBreakConfigSpan { + ctor @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public LineBreakConfigSpan.NoBreakSpan(); + } + @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final class LineBreakConfigSpan.NoHyphenationSpan extends android.text.style.LineBreakConfigSpan { ctor @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public LineBreakConfigSpan.NoHyphenationSpan(); } diff --git a/core/api/test-current.txt b/core/api/test-current.txt index db751a432dd7..b87a6407a195 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1903,7 +1903,7 @@ package android.media { method public android.media.PlaybackParams setAudioStretchMode(int); } - public final class RingtoneSelection { + @FlaggedApi("android.os.vibrator.haptics_customization_enabled") public final class RingtoneSelection { method @NonNull public static android.media.RingtoneSelection fromUri(@Nullable android.net.Uri, int); method public int getSoundSource(); method @Nullable public android.net.Uri getSoundUri(); @@ -1915,14 +1915,16 @@ package android.media { field public static final int FROM_URI_RINGTONE_SELECTION_ONLY = 3; // 0x3 field public static final int FROM_URI_RINGTONE_SELECTION_OR_SOUND = 1; // 0x1 field public static final int FROM_URI_RINGTONE_SELECTION_OR_VIBRATION = 2; // 0x2 - field public static final int SOUND_SOURCE_DEFAULT = 0; // 0x0 field public static final int SOUND_SOURCE_OFF = 1; // 0x1 + field public static final int SOUND_SOURCE_SYSTEM_DEFAULT = 3; // 0x3 + field public static final int SOUND_SOURCE_UNSPECIFIED = 0; // 0x0 field public static final int SOUND_SOURCE_URI = 2; // 0x2 - field public static final int VIBRATION_SOURCE_APPLICATION_PROVIDED = 3; // 0x3 + field public static final int VIBRATION_SOURCE_APPLICATION_DEFAULT = 4; // 0x4 field public static final int VIBRATION_SOURCE_AUDIO_CHANNEL = 10; // 0xa - field public static final int VIBRATION_SOURCE_DEFAULT = 0; // 0x0 field public static final int VIBRATION_SOURCE_HAPTIC_GENERATOR = 11; // 0xb field public static final int VIBRATION_SOURCE_OFF = 1; // 0x1 + field public static final int VIBRATION_SOURCE_SYSTEM_DEFAULT = 3; // 0x3 + field public static final int VIBRATION_SOURCE_UNSPECIFIED = 0; // 0x0 field public static final int VIBRATION_SOURCE_URI = 2; // 0x2 } @@ -2610,17 +2612,17 @@ package android.os.vibrator { package android.os.vibrator.persistence { - public class ParsedVibration { + @FlaggedApi("android.os.vibrator.enable_vibration_serialization_apis") public class ParsedVibration { method @NonNull public java.util.List<android.os.VibrationEffect> getVibrationEffects(); method @Nullable public android.os.VibrationEffect resolve(@NonNull android.os.Vibrator); } - public final class VibrationXmlParser { + @FlaggedApi("android.os.vibrator.enable_vibration_serialization_apis") public final class VibrationXmlParser { method @Nullable public static android.os.vibrator.persistence.ParsedVibration parseDocument(@NonNull java.io.Reader) throws java.io.IOException; method @Nullable public static android.os.VibrationEffect parseVibrationEffect(@NonNull java.io.Reader) throws java.io.IOException; } - public final class VibrationXmlSerializer { + @FlaggedApi("android.os.vibrator.enable_vibration_serialization_apis") public final class VibrationXmlSerializer { method public static void serialize(@NonNull android.os.VibrationEffect, @NonNull java.io.Writer) throws java.io.IOException, android.os.vibrator.persistence.VibrationXmlSerializer.SerializationFailedException; } @@ -3281,12 +3283,12 @@ package android.text { } public class MeasuredParagraph { - method @NonNull public static android.text.MeasuredParagraph buildForStaticLayoutTest(@NonNull android.text.TextPaint, @Nullable android.graphics.text.LineBreakConfig, @NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.text.TextDirectionHeuristic, int, boolean, @Nullable android.text.MeasuredParagraph.StyleRunCallback); + method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public static android.text.MeasuredParagraph buildForStaticLayoutTest(@NonNull android.text.TextPaint, @Nullable android.graphics.text.LineBreakConfig, @NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.text.TextDirectionHeuristic, int, boolean, @Nullable android.text.MeasuredParagraph.StyleRunCallback); } - public static interface MeasuredParagraph.StyleRunCallback { - method public void onAppendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @FloatRange(from=0) @Px float); - method public void onAppendStyleRun(@NonNull android.graphics.Paint, @Nullable android.graphics.text.LineBreakConfig, @IntRange(from=0) int, boolean); + @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static interface MeasuredParagraph.StyleRunCallback { + method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public void onAppendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @FloatRange(from=0) @Px float); + method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public void onAppendStyleRun(@NonNull android.graphics.Paint, @Nullable android.graphics.text.LineBreakConfig, @IntRange(from=0) int, boolean); } public static final class Selection.MemoryTextWatcher implements android.text.TextWatcher { diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt index 107be8be42e2..93e39d5f41f7 100644 --- a/core/api/test-lint-baseline.txt +++ b/core/api/test-lint-baseline.txt @@ -191,8 +191,14 @@ UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_DEFAULT: New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_DEFAULT UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_OFF: New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_OFF +UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_SYSTEM_DEFAULT: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_SYSTEM_DEFAULT +UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_UNSPECIFIED: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_UNSPECIFIED UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_URI: New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_URI +UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_APPLICATION_DEFAULT: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_APPLICATION_DEFAULT UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_APPLICATION_PROVIDED: New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_APPLICATION_PROVIDED UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_AUDIO_CHANNEL: @@ -203,6 +209,10 @@ UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_HAPTIC_GENERATOR: New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_HAPTIC_GENERATOR UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_OFF: New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_OFF +UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_SYSTEM_DEFAULT: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_SYSTEM_DEFAULT +UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_UNSPECIFIED: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_UNSPECIFIED UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_URI: New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_URI UnflaggedApi: android.media.RingtoneSelection#fromUri(android.net.Uri, int): diff --git a/core/java/Android.bp b/core/java/Android.bp index 13a1bd6ca176..c3f3d875b0e0 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -431,6 +431,16 @@ aidl_interface { }, } +aidl_interface { + name: "android.companion.virtual.virtualdevice_aidl", + unstable: true, + host_supported: true, + srcs: [ + "android/companion/virtualnative/IVirtualDeviceManagerNative.aidl", + ], + local_include_dir: ".", +} + filegroup { name: "frameworks-base-java-overview", srcs: ["overview.html"], diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 3bf2ccaf9923..f68681b54e48 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -4288,7 +4288,7 @@ public class ActivityManager { } /** - * Start monitoring changes to the imoportance of uids running in the system. + * Start monitoring changes to the importance of uids running in the system. * @param listener The listener callback that will receive change reports. * @param importanceCutpoint The level of importance in which the caller is interested * in differences. For example, if {@link RunningAppProcessInfo#IMPORTANCE_PERCEPTIBLE} diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 9a90df93b2cd..e12181a08db3 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -101,6 +101,7 @@ import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; +import android.content.res.ResourcesImpl; import android.content.res.loader.ResourcesLoader; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDebug; @@ -297,6 +298,7 @@ public final class ActivityThread extends ClientTransactionHandler public static final boolean DEBUG_MEMORY_TRIM = false; private static final boolean DEBUG_PROVIDER = false; public static final boolean DEBUG_ORDER = false; + private static final boolean DEBUG_APP_INFO = true; private static final long MIN_TIME_BETWEEN_GCS = 5*1000; /** * The delay to release the provider when it has no more references. It reduces the number of @@ -6473,10 +6475,35 @@ public final class ActivityThread extends ClientTransactionHandler resApk.updateApplicationInfo(ai, oldPaths); } + ResourcesImpl beforeImpl = getApplication().getResources().getImpl(); + synchronized (mResourcesManager) { // Update all affected Resources objects to use new ResourcesImpl mResourcesManager.applyAllPendingAppInfoUpdates(); } + + ResourcesImpl afterImpl = getApplication().getResources().getImpl(); + + if ((beforeImpl != afterImpl) && !Arrays.equals(beforeImpl.getAssets().getApkAssets(), + afterImpl.getAssets().getApkAssets())) { + List<String> beforeAssets = Arrays.asList(beforeImpl.getAssets().getApkPaths()); + List<String> afterAssets = Arrays.asList(afterImpl.getAssets().getApkPaths()); + + List<String> onlyBefore = new ArrayList<>(beforeAssets); + onlyBefore.removeAll(afterAssets); + List<String> onlyAfter = new ArrayList<>(afterAssets); + onlyAfter.removeAll(beforeAssets); + + Slog.i(TAG, "ApplicationInfo updating for " + ai.packageName + ", new timestamp: " + + ai.createTimestamp + "\nassets removed: " + onlyBefore + "\nassets added: " + + onlyAfter); + + if (DEBUG_APP_INFO) { + Slog.v(TAG, "ApplicationInfo updating for " + ai.packageName + + ", assets before change: " + beforeAssets + "\n assets after change: " + + afterAssets); + } + } } /** diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index ca10d144d4cd..68589456dec3 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1478,7 +1478,8 @@ public class AppOpsManager { AppProtoEnums.APP_OP_RECORD_AUDIO_SANDBOXED; /** - * Allows the assistant app to receive the PCC-validated hotword and be voice-triggered. + * Allows the assistant app to be voice-triggered by detected hotwords from a trusted detection + * service. * * @hide */ @@ -1486,13 +1487,13 @@ public class AppOpsManager { AppProtoEnums.APP_OP_RECEIVE_SANDBOX_TRIGGER_AUDIO; /** - * Allows the assistant app to get the training data from the PCC sandbox to improve the + * Allows the assistant app to get the training data from the trusted process to improve the * hotword training model. * * @hide */ - public static final int OP_RECEIVE_SANDBOX_TRAINING_DATA = - AppProtoEnums.APP_OP_RECEIVE_SANDBOX_TRAINING_DATA; + public static final int OP_RECEIVE_TRUSTED_PROCESS_TRAINING_DATA = + AppProtoEnums.APP_OP_RECEIVE_TRUSTED_PROCESS_TRAINING_DATA; /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -1640,7 +1641,7 @@ public class AppOpsManager { OPSTR_CAMERA_SANDBOXED, OPSTR_RECORD_AUDIO_SANDBOXED, OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO, - OPSTR_RECEIVE_SANDBOX_TRAINING_DATA + OPSTR_RECEIVE_TRUSTED_PROCESS_TRAINING_DATA }) public @interface AppOpString {} @@ -2252,7 +2253,8 @@ public class AppOpsManager { public static final String OPSTR_USE_FULL_SCREEN_INTENT = "android:use_full_screen_intent"; /** - * Allows the assistant app to receive the PCC-validated hotword and be voice-triggered. + * Allows the assistant app to be voice-triggered by detected hotwords from a trusted detection + * service. * * @hide */ @@ -2261,13 +2263,13 @@ public class AppOpsManager { "android:receive_sandbox_trigger_audio"; /** - * Allows the assistant app to get the training data from the PCC sandbox to improve + * Allows the assistant app to get the training data from the trusted process to improve * the hotword training model. * * @hide */ - public static final String OPSTR_RECEIVE_SANDBOX_TRAINING_DATA = - "android:receive_sandbox_training_data"; + public static final String OPSTR_RECEIVE_TRUSTED_PROCESS_TRAINING_DATA = + "android:receive_trusted_process_training_data"; /** {@link #sAppOpsToNote} not initialized yet for this op */ private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0; @@ -2379,7 +2381,8 @@ public class AppOpsManager { OP_RUN_USER_INITIATED_JOBS, OP_FOREGROUND_SERVICE_SPECIAL_USE, OP_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD, - OP_USE_FULL_SCREEN_INTENT + OP_USE_FULL_SCREEN_INTENT, + OP_RECEIVE_SANDBOX_TRIGGER_AUDIO }; static final AppOpInfo[] sAppOpInfos = new AppOpInfo[]{ @@ -2810,10 +2813,11 @@ public class AppOpsManager { new AppOpInfo.Builder(OP_RECEIVE_SANDBOX_TRIGGER_AUDIO, OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO, "RECEIVE_SANDBOX_TRIGGER_AUDIO") - .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(), - new AppOpInfo.Builder(OP_RECEIVE_SANDBOX_TRAINING_DATA, - OPSTR_RECEIVE_SANDBOX_TRAINING_DATA, - "RECEIVE_SANDBOX_TRAINING_DATA").build() + .setPermission(Manifest.permission.RECEIVE_SANDBOX_TRIGGER_AUDIO) + .setDefaultMode(AppOpsManager.MODE_DEFAULT).build(), + new AppOpInfo.Builder(OP_RECEIVE_TRUSTED_PROCESS_TRAINING_DATA, + OPSTR_RECEIVE_TRUSTED_PROCESS_TRAINING_DATA, + "RECEIVE_TRUSTED_PROCESS_TRAINING_DATA").build() }; // The number of longs needed to form a full bitmask of app ops diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index e5a73be5023a..21ed098f448a 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -2954,6 +2954,17 @@ public class ApplicationPackageManager extends PackageManager { } } + @Override + public boolean isPackageStopped(@NonNull String packageName) throws NameNotFoundException { + try { + return mPM.isPackageStoppedForUser(packageName, getUserId()); + } catch (IllegalArgumentException ie) { + throw new NameNotFoundException(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** @hide */ @Override public void setApplicationCategoryHint(String packageName, int categoryHint) { diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig index d0e13cd977ef..cf274f5cbbb9 100644 --- a/core/java/android/companion/virtual/flags.aconfig +++ b/core/java/android/companion/virtual/flags.aconfig @@ -8,6 +8,14 @@ flag { } flag { + name: "enable_native_vdm" + namespace: "virtual_devices" + description: "Enable native VDM service" + bug: "303535376" + is_fixed_read_only: true +} + +flag { name: "dynamic_policy" namespace: "virtual_devices" description: "Enable dynamic policy API" diff --git a/core/java/android/companion/virtualnative/IVirtualDeviceManagerNative.aidl b/core/java/android/companion/virtualnative/IVirtualDeviceManagerNative.aidl new file mode 100644 index 000000000000..9f09d043a89b --- /dev/null +++ b/core/java/android/companion/virtualnative/IVirtualDeviceManagerNative.aidl @@ -0,0 +1,65 @@ +/* + * 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.companion.virtualnative; + +/** + * Parallel implementation of certain VirtualDeviceManager APIs that need to be exposed to native + * code. + * + * <p>These APIs are a parallel definition to the APIs in VirtualDeviceManager and/or + * VirtualDeviceManagerInternal, so they can technically diverge. However, it's good practice to + * keep these APIs in sync with each other.</p> + * + * <p>Even though the name implies otherwise, the implementation is actually in Java. The 'native' + * suffix comes from the intended usage - native framework backends that need to communicate with + * VDM for some reason.</p> + * + * <p>Because these APIs are exposed to native code that runs in the app process, they may be + * accessed by apps directly, even though they're hidden. Care should be taken to avoid exposing + * sensitive data or potential security holes.</p> + * + * @hide + */ +interface IVirtualDeviceManagerNative { + /** + * Counterpart to VirtualDeviceParams#DevicePolicy. + */ + const int DEVICE_POLICY_DEFAULT = 0; + const int DEVICE_POLICY_CUSTOM = 1; + + /** + * Counterpart to VirtualDeviceParams#PolicyType. + */ + const int POLICY_TYPE_SENSORS = 0; + const int POLICY_TYPE_AUDIO = 1; + const int POLICY_TYPE_RECENTS = 2; + const int POLICY_TYPE_ACTIVITY = 3; + + /** + * Returns the IDs for all VirtualDevices where an app with the given is running. + * + * Note that this returns only VirtualDevice IDs: if the app is not running on any virtual + * device, then an an empty array is returned. This does not include information about whether + * the app is running on the default device or not. + */ + int[] getDeviceIdsForUid(int uid); + + /** + * Returns the device policy for the given virtual device and policy type. + */ + int getDevicePolicy(int deviceId, int policyType); +}
\ No newline at end of file diff --git a/core/java/android/companion/virtualnative/OWNERS b/core/java/android/companion/virtualnative/OWNERS new file mode 100644 index 000000000000..29681045ac4a --- /dev/null +++ b/core/java/android/companion/virtualnative/OWNERS @@ -0,0 +1 @@ +include /services/companion/java/com/android/server/companion/virtual/OWNERS diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 44a9acd6ba2f..5f4c05f001ff 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2790,6 +2790,20 @@ public class Intent implements Parcelable, Cloneable { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED"; + + /** + * Broadcast Action: An application package that was previously in the stopped state has been + * started and is no longer considered stopped. + * <ul> + * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package. + * </ul> + * + * <p class="note">This is a protected intent that can only be sent by the system. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @FlaggedApi(android.content.pm.Flags.FLAG_STAY_STOPPED) + public static final String ACTION_PACKAGE_UNSTOPPED = "android.intent.action.PACKAGE_UNSTOPPED"; + /** * Broadcast Action: Sent to the system rollback manager when a package * needs to have rollback enabled. diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index aca88d6af033..99264150f7d0 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -308,6 +308,8 @@ interface IPackageManager { boolean isPackageQuarantinedForUser(String packageName, int userId); + boolean isPackageStoppedForUser(String packageName, int userId); + Bundle getSuspendedPackageAppExtras(String packageName, int userId); /** diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 3a9e9bf01f04..673a8a5edcba 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -371,13 +371,6 @@ public class PackageInstaller { "android.content.pm.extra.UNARCHIVE_ALL_USERS"; /** - * A list of warnings that occurred during installation. - * - * @hide - */ - public static final String EXTRA_WARNINGS = "android.content.pm.extra.WARNINGS"; - - /** * Streaming installation pending. * Caller should make sure DataLoader is able to prepare image and reinitiate the operation. * diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 8fbe50c32881..45338bb2c0a2 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -9878,6 +9878,18 @@ public abstract class PackageManager { } /** + * Query if an app is currently stopped. + * + * @return {@code true} if the given package is stopped, {@code false} otherwise + * @throws NameNotFoundException if the package could not be found. + * @see ApplicationInfo#FLAG_STOPPED + */ + @FlaggedApi(android.content.pm.Flags.FLAG_STAY_STOPPED) + public boolean isPackageStopped(@NonNull String packageName) throws NameNotFoundException { + throw new UnsupportedOperationException("isPackageStopped not implemented"); + } + + /** * Query if an app is currently quarantined. * * @return {@code true} if the given package is quarantined, {@code false} otherwise @@ -9888,7 +9900,6 @@ public abstract class PackageManager { public boolean isPackageQuarantined(@NonNull String packageName) throws NameNotFoundException { throw new UnsupportedOperationException("isPackageQuarantined not implemented"); } - /** * Provide a hint of what the {@link ApplicationInfo#category} value should * be for the given package. diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig index ea0f049cece3..3ec239c7125e 100644 --- a/core/java/android/content/pm/multiuser.aconfig +++ b/core/java/android/content/pm/multiuser.aconfig @@ -8,8 +8,23 @@ flag { } flag { + name: "save_global_and_guest_restrictions_on_system_user_xml_read_only" + namespace: "multiuser" + description: "Save guest and device policy global restrictions on the SYSTEM user's XML file. (Read only flag)" + bug: "301067944" + is_fixed_read_only: true +} + +flag { name: "bind_wallpaper_service_on_its_own_thread_during_a_user_switch" namespace: "multiuser" description: "Bind wallpaper service on its own thread instead of system_server's main handler during a user switch." bug: "302100344" } + +flag { + name: "support_communal_profile" + namespace: "multiuser" + description: "Framework support for communal profile." + bug: "285426179" +} diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.java b/core/java/android/credentials/GetCandidateCredentialsResponse.java index 231e4bc4ac75..1b130a9fb64d 100644 --- a/core/java/android/credentials/GetCandidateCredentialsResponse.java +++ b/core/java/android/credentials/GetCandidateCredentialsResponse.java @@ -53,6 +53,15 @@ public final class GetCandidateCredentialsResponse implements Parcelable { mCandidateProviderDataList = new ArrayList<>(candidateProviderDataList); } + /** + * Returns candidate provider data list. + * + * @hide + */ + public List<GetCredentialProviderData> getCandidateProviderDataList() { + return mCandidateProviderDataList; + } + protected GetCandidateCredentialsResponse(Parcel in) { List<GetCredentialProviderData> candidateProviderDataList = new ArrayList<>(); in.readTypedList(candidateProviderDataList, GetCredentialProviderData.CREATOR); diff --git a/core/java/android/hardware/input/KeyboardLayout.java b/core/java/android/hardware/input/KeyboardLayout.java index bbfed24f9dc1..883f157bbfe5 100644 --- a/core/java/android/hardware/input/KeyboardLayout.java +++ b/core/java/android/hardware/input/KeyboardLayout.java @@ -82,8 +82,8 @@ public final class KeyboardLayout implements Parcelable, Comparable<KeyboardLayo DVORAK(4, LAYOUT_TYPE_DVORAK), COLEMAK(5, LAYOUT_TYPE_COLEMAK), WORKMAN(6, LAYOUT_TYPE_WORKMAN), - TURKISH_F(7, LAYOUT_TYPE_TURKISH_F), - TURKISH_Q(8, LAYOUT_TYPE_TURKISH_Q), + TURKISH_Q(7, LAYOUT_TYPE_TURKISH_Q), + TURKISH_F(8, LAYOUT_TYPE_TURKISH_F), EXTENDED(9, LAYOUT_TYPE_EXTENDED); private final int mValue; diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig index d8e60c8b6464..88f62f327fdd 100644 --- a/core/java/android/os/vibrator/flags.aconfig +++ b/core/java/android/os/vibrator/flags.aconfig @@ -19,4 +19,11 @@ flag { name: "haptics_customization_ringtone_v2_enabled" description: "Enables the usage of the new RingtoneV2 class" bug: "241918098" -}
\ No newline at end of file +} + +flag { + namespace: "haptics" + name: "enable_vibration_serialization_apis" + description: "Enables the APIs for vibration serialization/deserialization." + bug: "245129509" +} diff --git a/core/java/android/os/vibrator/persistence/ParsedVibration.java b/core/java/android/os/vibrator/persistence/ParsedVibration.java index ded74eab149e..3d1deea57f14 100644 --- a/core/java/android/os/vibrator/persistence/ParsedVibration.java +++ b/core/java/android/os/vibrator/persistence/ParsedVibration.java @@ -16,6 +16,7 @@ package android.os.vibrator.persistence; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; @@ -34,6 +35,7 @@ import java.util.List; * * @hide */ +@FlaggedApi(android.os.vibrator.Flags.FLAG_ENABLE_VIBRATION_SERIALIZATION_APIS) @TestApi public class ParsedVibration { private final List<VibrationEffect> mEffects; diff --git a/core/java/android/os/vibrator/persistence/VibrationXmlParser.java b/core/java/android/os/vibrator/persistence/VibrationXmlParser.java index e08cc4262bed..fed1053e2a12 100644 --- a/core/java/android/os/vibrator/persistence/VibrationXmlParser.java +++ b/core/java/android/os/vibrator/persistence/VibrationXmlParser.java @@ -16,6 +16,7 @@ package android.os.vibrator.persistence; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -115,6 +116,7 @@ import java.util.List; * * @hide */ +@FlaggedApi(android.os.vibrator.Flags.FLAG_ENABLE_VIBRATION_SERIALIZATION_APIS) @TestApi public final class VibrationXmlParser { private static final String TAG = "VibrationXmlParser"; diff --git a/core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java b/core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java index 1cdfa4f74dbd..28804544edaf 100644 --- a/core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java +++ b/core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java @@ -16,6 +16,7 @@ package android.os.vibrator.persistence; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.TestApi; @@ -42,6 +43,7 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ +@FlaggedApi(android.os.vibrator.Flags.FLAG_ENABLE_VIBRATION_SERIALIZATION_APIS) @TestApi public final class VibrationXmlSerializer { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index b414ed4faea2..5c64389e8c27 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -4866,7 +4866,8 @@ public final class Settings { "display_color_mode_vendor_hint"; /** - * The user selected min refresh rate in frames per second. + * The user selected min refresh rate in frames per second. If infinite, the user wants + * the highest possible refresh rate. * * If this isn't set, 0 will be used. * @hide @@ -4875,7 +4876,8 @@ public final class Settings { public static final String MIN_REFRESH_RATE = "min_refresh_rate"; /** - * The user selected peak refresh rate in frames per second. + * The user selected peak refresh rate in frames per second. If infinite, the user wants + * the highest possible refresh rate. * * If this isn't set, the system falls back to a device specific default. * @hide @@ -11607,6 +11609,45 @@ public final class Settings { "accessibility_magnification_joystick_enabled"; /** + * Controls magnification enable gesture. Accessibility magnification can have one or more + * enable gestures. + * + * @see #ACCESSIBILITY_MAGNIFICATION_GESTURE_NONE + * @see #ACCESSIBILITY_MAGNIFICATION_GESTURE_SINGLE_FINGER_TRIPLE_TAP + * @see #ACCESSIBILITY_MAGNIFICATION_GESTURE_TWO_FINGER_TRIPLE_TAP + * @hide + */ + public static final String ACCESSIBILITY_MAGNIFICATION_GESTURE = + "accessibility_magnification_gesture"; + + /** + * Magnification enable gesture value that is a default value. + * @hide + */ + public static final int ACCESSIBILITY_MAGNIFICATION_GESTURE_NONE = 0x0; + + /** + * Magnification enable gesture value is single finger triple tap. + * @hide + */ + public static final int ACCESSIBILITY_MAGNIFICATION_GESTURE_SINGLE_FINGER_TRIPLE_TAP = 0x1; + + /** + * Magnification enable gesture value is two finger triple tap. + * @hide + */ + public static final int ACCESSIBILITY_MAGNIFICATION_GESTURE_TWO_FINGER_TRIPLE_TAP = 0x2; + + /** + * Magnification enable gesture values include single finger triple tap and two finger + * triple tap. + * @hide + */ + public static final int ACCESSIBILITY_MAGNIFICATION_GESTURE_ALL = + ACCESSIBILITY_MAGNIFICATION_GESTURE_SINGLE_FINGER_TRIPLE_TAP + | ACCESSIBILITY_MAGNIFICATION_GESTURE_TWO_FINGER_TRIPLE_TAP; + + /** * Controls magnification capability. Accessibility magnification is capable of at least one * of the magnification modes. * diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java index 115894f586f2..a29bf7a06334 100644 --- a/core/java/android/service/autofill/Dataset.java +++ b/core/java/android/service/autofill/Dataset.java @@ -18,6 +18,7 @@ package android.service.autofill; import static android.view.autofill.Helper.sDebug; +import android.annotation.Hide; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -26,6 +27,7 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.content.ClipData; import android.content.IntentSender; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.util.ArrayMap; @@ -187,6 +189,9 @@ public final class Dataset implements Parcelable { @Nullable private final InlinePresentation mInlinePresentation; @Nullable private final InlinePresentation mInlineTooltipPresentation; private final IntentSender mAuthentication; + + @Nullable private final Bundle mAuthenticationExtras; + @Nullable String mId; /** @@ -224,6 +229,7 @@ public final class Dataset implements Parcelable { mInlinePresentation = inlinePresentation; mInlineTooltipPresentation = inlineTooltipPresentation; mAuthentication = authentication; + mAuthenticationExtras = null; mId = id; } @@ -246,6 +252,7 @@ public final class Dataset implements Parcelable { mInlinePresentation = dataset.mInlinePresentation; mInlineTooltipPresentation = dataset.mInlineTooltipPresentation; mAuthentication = dataset.mAuthentication; + mAuthenticationExtras = dataset.mAuthenticationExtras; mId = dataset.mId; mAutofillDatatypes = dataset.mAutofillDatatypes; } @@ -264,6 +271,7 @@ public final class Dataset implements Parcelable { mInlinePresentation = builder.mInlinePresentation; mInlineTooltipPresentation = builder.mInlineTooltipPresentation; mAuthentication = builder.mAuthentication; + mAuthenticationExtras = builder.mAuthenticationExtras; mId = builder.mId; mAutofillDatatypes = builder.mAutofillDatatypes; } @@ -345,6 +353,12 @@ public final class Dataset implements Parcelable { } /** @hide */ + @Hide + public @Nullable Bundle getAuthenticationExtras() { + return mAuthenticationExtras; + } + + /** @hide */ @TestApi public boolean isEmpty() { return mFieldIds == null || mFieldIds.isEmpty(); @@ -401,6 +415,9 @@ public final class Dataset implements Parcelable { if (mAuthentication != null) { builder.append(", hasAuthentication"); } + if (mAuthenticationExtras != null) { + builder.append(", hasAuthenticationExtras"); + } if (mAutofillDatatypes != null) { builder.append(", autofillDatatypes=").append(mAutofillDatatypes); } @@ -454,6 +471,8 @@ public final class Dataset implements Parcelable { @Nullable private InlinePresentation mInlinePresentation; @Nullable private InlinePresentation mInlineTooltipPresentation; private IntentSender mAuthentication; + + private Bundle mAuthenticationExtras; private boolean mDestroyed; @Nullable private String mId; @@ -624,6 +643,25 @@ public final class Dataset implements Parcelable { } /** + * Sets extras to be associated with the {@code authentication} intent sender, to be + * set on the intent that is fired through the intent sender. + * + * Autofill providers can set any extras they wish to receive directly on the intent + * that is used to create the {@code authentication}. This is an internal API, to be + * used by the platform to associate data with a given dataset. These extras will be + * merged with the {@code clientState} and sent as part of the fill in intent when + * the {@code authentication} intentSender is invoked. + * + * @hide + */ + @Hide + public @NonNull Builder setAuthenticationExtras(@Nullable Bundle authenticationExtra) { + throwIfDestroyed(); + mAuthenticationExtras = authenticationExtra; + return this; + } + + /** * Sets the id for the dataset so its usage can be tracked. * * <p>Dataset usage can be tracked for 2 purposes: diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java index be7b72202b3f..a2b0a669c768 100644 --- a/core/java/android/service/credentials/CredentialProviderService.java +++ b/core/java/android/service/credentials/CredentialProviderService.java @@ -153,6 +153,18 @@ public abstract class CredentialProviderService extends Service { public static final String EXTRA_BEGIN_GET_CREDENTIAL_REQUEST = "android.service.credentials.extra.BEGIN_GET_CREDENTIAL_REQUEST"; + /** + * The key to autofillId associated with the requested credential option and the corresponding + * credential entry. The associated autofillId will be contained inside the candidate query + * bundle of {@link android.credentials.CredentialOption} if requested through the + * {@link com.android.credentialmanager.autofill.CredentialAutofillService}. The resulting + * credential entry will contain the autofillId inside its framework extras intent. + * + * @hide + */ + public static final String EXTRA_AUTOFILL_ID = + "android.service.credentials.extra.AUTOFILL_ID"; + private static final String TAG = "CredProviderService"; /** diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 07f8aac43bf5..1cfff14b2d7c 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -2007,6 +2007,20 @@ public abstract class NotificationListenerService extends Service { return mSmartActions == null ? Collections.emptyList() : mSmartActions; } + + /** + * Sets the smart {@link Notification.Action} objects. + * + * Should ONLY be used in cases where smartActions need to be removed from, then restored + * on, Ranking objects during Parceling, when they are transmitted between processes via + * Shared Memory. + * + * @hide + */ + public void setSmartActions(@Nullable ArrayList<Notification.Action> smartActions) { + mSmartActions = smartActions; + } + /** * Returns a list of smart replies that can be added by the * {@link NotificationAssistantService} @@ -2353,11 +2367,9 @@ public abstract class NotificationListenerService extends Service { /** * Get a reference to the actual Ranking object corresponding to the key. - * Used only by unit tests. * * @hide */ - @VisibleForTesting public Ranking getRawRankingObject(String key) { return mRankings.get(key); } diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java index f3b4c6da4a01..0dad96eb3b5b 100644 --- a/core/java/android/service/notification/NotificationRankingUpdate.java +++ b/core/java/android/service/notification/NotificationRankingUpdate.java @@ -18,6 +18,8 @@ package android.service.notification; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.TestApi; +import android.app.Notification; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.os.SharedMemory; @@ -29,9 +31,12 @@ import androidx.annotation.NonNull; import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; /** * Represents an update to notification rankings. + * * @hide */ @SuppressLint({"ParcelNotFinal", "ParcelCreator"}) @@ -64,6 +69,7 @@ public class NotificationRankingUpdate implements Parcelable { // The ranking map should be stored in shared memory when it is parceled, so we // unwrap the SharedMemory object. mRankingMapFd = in.readParcelable(getClass().getClassLoader(), SharedMemory.class); + Bundle smartActionsBundle = in.readBundle(getClass().getClassLoader()); // In the case that the ranking map can't be read, readParcelable may return null. // In this case, we set mRankingMap to null; @@ -82,8 +88,13 @@ public class NotificationRankingUpdate implements Parcelable { mapParcel.unmarshall(payload, 0, payload.length); mapParcel.setDataPosition(0); - mRankingMap = mapParcel.readParcelable(getClass().getClassLoader(), - android.service.notification.NotificationListenerService.RankingMap.class); + mRankingMap = + mapParcel.readParcelable( + getClass().getClassLoader(), + NotificationListenerService.RankingMap.class); + + addSmartActionsFromBundleToRankingMap(smartActionsBundle); + } catch (ErrnoException e) { // TODO(b/284297289): remove throw when associated flag is moved to droidfood, to // avoid crashes; change to Log.wtf. @@ -102,7 +113,31 @@ public class NotificationRankingUpdate implements Parcelable { } /** + * For each key in the rankingMap, extracts lists of smart actions stored in the provided + * bundle and adds them to the corresponding Ranking object in the provided ranking + * map, then returns the rankingMap. + * + * @hide + */ + private void addSmartActionsFromBundleToRankingMap(Bundle smartActionsBundle) { + if (smartActionsBundle == null) { + return; + } + + String[] rankingMapKeys = mRankingMap.getOrderedKeys(); + for (int i = 0; i < rankingMapKeys.length; i++) { + String key = rankingMapKeys[i]; + ArrayList<Notification.Action> smartActions = + smartActionsBundle.getParcelableArrayList(key, Notification.Action.class); + // Get the ranking object from the ranking map. + NotificationListenerService.Ranking ranking = mRankingMap.getRawRankingObject(key); + ranking.setSmartActions(smartActions); + } + } + + /** * Confirms that the SharedMemory file descriptor is closed. Should only be used for testing. + * * @hide */ @TestApi @@ -145,9 +180,45 @@ public class NotificationRankingUpdate implements Parcelable { if (SystemUiSystemPropertiesFlags.getResolver().isEnabled( SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM)) { final Parcel mapParcel = Parcel.obtain(); + ArrayList<NotificationListenerService.Ranking> marshalableRankings = new ArrayList<>(); + Bundle smartActionsBundle = new Bundle(); + + // We need to separate the SmartActions from the RankingUpdate objects. + // SmartActions can contain PendingIntents, which cannot be marshalled, + // so we extract them to send separately. + String[] rankingMapKeys = mRankingMap.getOrderedKeys(); + for (int i = 0; i < rankingMapKeys.length; i++) { + String key = rankingMapKeys[i]; + NotificationListenerService.Ranking ranking = mRankingMap.getRawRankingObject(key); + + // Removes the SmartActions and stores them in a separate map. + // Note that getSmartActions returns a Collections.emptyList() if there are no + // smart actions, and we don't want to needlessly store an empty list object, so we + // check for null before storing. + List<Notification.Action> smartActions = ranking.getSmartActions(); + if (!smartActions.isEmpty()) { + smartActionsBundle.putParcelableList(key, smartActions); + } + + // Create a copy of the ranking object that doesn't have the smart actions. + NotificationListenerService.Ranking rankingCopy = + new NotificationListenerService.Ranking(); + rankingCopy.populate(ranking); + rankingCopy.setSmartActions(null); + marshalableRankings.add(rankingCopy); + } + + // Create a new marshalable RankingMap. + NotificationListenerService.RankingMap marshalableRankingMap = + new NotificationListenerService.RankingMap( + marshalableRankings.toArray( + new NotificationListenerService.Ranking[0] + ) + ); + try { // Parcels the ranking map and measures its size. - mapParcel.writeParcelable(mRankingMap, flags); + mapParcel.writeParcelable(marshalableRankingMap, flags); int mapSize = mapParcel.dataSize(); // Creates a new SharedMemory object with enough space to hold the ranking map. @@ -158,15 +229,14 @@ public class NotificationRankingUpdate implements Parcelable { // Gets a read/write buffer mapping the entire shared memory region. final ByteBuffer buffer = mRankingMapFd.mapReadWrite(); - // Puts the ranking map into the shared memory region buffer. buffer.put(mapParcel.marshall(), 0, mapSize); - // Protects the region from being written to, by setting it to be read-only. mRankingMapFd.setProtect(OsConstants.PROT_READ); - // Puts the SharedMemory object in the parcel. out.writeParcelable(mRankingMapFd, flags); + // Writes the Parceled smartActions separately. + out.writeBundle(smartActionsBundle); } catch (ErrnoException e) { // TODO(b/284297289): remove throw when associated flag is moved to droidfood, to // avoid crashes; change to Log.wtf. @@ -180,8 +250,8 @@ public class NotificationRankingUpdate implements Parcelable { } /** - * @hide - */ + * @hide + */ public static final @android.annotation.NonNull Parcelable.Creator<NotificationRankingUpdate> CREATOR = new Parcelable.Creator<NotificationRankingUpdate>() { public NotificationRankingUpdate createFromParcel(Parcel parcel) { diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index f6309f2c9860..cf1156db55e5 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -401,7 +401,7 @@ public class PhoneStateListener { /** * Listen for call disconnect causes which contains {@link DisconnectCause} and - * {@link PreciseDisconnectCause}. + * the precise disconnect cause. * * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} * or the calling app has carrier privileges @@ -851,8 +851,8 @@ public class PhoneStateListener { * subId. Otherwise, this callback applies to * {@link SubscriptionManager#getDefaultSubscriptionId()}. * - * @param disconnectCause {@link DisconnectCause}. - * @param preciseDisconnectCause {@link PreciseDisconnectCause}. + * @param disconnectCause the disconnect cause + * @param preciseDisconnectCause the precise disconnect cause * @deprecated Use {@link TelephonyCallback.CallDisconnectCauseListener} instead. */ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) diff --git a/core/java/android/telephony/SubscriptionPlan.java b/core/java/android/telephony/SubscriptionPlan.java index fb2d7714d402..7b48a16c2227 100644 --- a/core/java/android/telephony/SubscriptionPlan.java +++ b/core/java/android/telephony/SubscriptionPlan.java @@ -221,7 +221,7 @@ public final class SubscriptionPlan implements Parcelable { } /** - * Return an array containing all {@link NetworkType}s this SubscriptionPlan applies to. + * Return an array containing all network types this SubscriptionPlan applies to. * @see TelephonyManager for network types values */ public @NonNull @NetworkType int[] getNetworkTypes() { @@ -365,7 +365,7 @@ public final class SubscriptionPlan implements Parcelable { * Set the network types this SubscriptionPlan applies to. By default the plan will apply * to all network types. An empty array means this plan applies to no network types. * - * @param networkTypes an array of all {@link NetworkType}s that apply to this plan. + * @param networkTypes an array of all network types that apply to this plan. * @see TelephonyManager for network type values */ public @NonNull Builder setNetworkTypes(@NonNull @NetworkType int[] networkTypes) { diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java index 7ada058e8e80..19bcf28d6b83 100644 --- a/core/java/android/telephony/TelephonyCallback.java +++ b/core/java/android/telephony/TelephonyCallback.java @@ -948,8 +948,8 @@ public class TelephonyCallback { * subscription ID. Otherwise, this callback applies to * {@link SubscriptionManager#getDefaultSubscriptionId()}. * - * @param disconnectCause {@link DisconnectCause}. - * @param preciseDisconnectCause {@link PreciseDisconnectCause}. + * @param disconnectCause the disconnect cause + * @param preciseDisconnectCause the precise disconnect cause */ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) void onCallDisconnectCauseChanged(@Annotation.DisconnectCauses int disconnectCause, diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index e2c5539141a4..0063d13cb3ab 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -238,7 +238,7 @@ public class TelephonyRegistryManager { } /** - * To check the SDK version for {@link #listenFromListener}. + * To check the SDK version for {@code #listenFromListener}. */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P) diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index 2b3a081ceff6..8862f1d74ab1 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -16,6 +16,10 @@ package android.text; +import static com.android.text.flags.Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN; +import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH; + +import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntRange; import android.annotation.NonNull; @@ -280,6 +284,7 @@ public class DynamicLayout extends Layout { * @see android.widget.TextView#setLineBreakWordStyle */ @NonNull + @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) public Builder setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) { mLineBreakConfig = lineBreakConfig; return this; @@ -303,6 +308,7 @@ public class DynamicLayout extends Layout { * @see Layout.Builder#setUseBoundsForWidth(boolean) */ @NonNull + @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public Builder setUseBoundsForWidth(boolean useBoundsForWidth) { mUseBoundsForWidth = useBoundsForWidth; return this; diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java index c5857347fd45..94c8eaf13ccb 100644 --- a/core/java/android/text/FontConfig.java +++ b/core/java/android/text/FontConfig.java @@ -29,6 +29,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.graphics.fonts.FontFamily.Builder.VariableFontFamilyType; import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; +import android.icu.util.ULocale; import android.os.Build; import android.os.LocaleList; import android.os.Parcel; @@ -39,6 +40,7 @@ import java.lang.annotation.Retention; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Objects; @@ -58,6 +60,7 @@ public final class FontConfig implements Parcelable { private final @NonNull List<FontFamily> mFamilies; private final @NonNull List<Alias> mAliases; private final @NonNull List<NamedFamilyList> mNamedFamilyLists; + private final @NonNull List<Customization.LocaleFallback> mLocaleFallbackCustomizations; private final long mLastModifiedTimeMillis; private final int mConfigVersion; @@ -71,10 +74,12 @@ public final class FontConfig implements Parcelable { */ public FontConfig(@NonNull List<FontFamily> families, @NonNull List<Alias> aliases, @NonNull List<NamedFamilyList> namedFamilyLists, + @NonNull List<Customization.LocaleFallback> localeFallbackCustomizations, long lastModifiedTimeMillis, @IntRange(from = 0) int configVersion) { mFamilies = families; mAliases = aliases; mNamedFamilyLists = namedFamilyLists; + mLocaleFallbackCustomizations = localeFallbackCustomizations; mLastModifiedTimeMillis = lastModifiedTimeMillis; mConfigVersion = configVersion; } @@ -84,7 +89,8 @@ public final class FontConfig implements Parcelable { */ public FontConfig(@NonNull List<FontFamily> families, @NonNull List<Alias> aliases, long lastModifiedTimeMillis, @IntRange(from = 0) int configVersion) { - this(families, aliases, Collections.emptyList(), lastModifiedTimeMillis, configVersion); + this(families, aliases, Collections.emptyList(), Collections.emptyList(), + lastModifiedTimeMillis, configVersion); } @@ -113,6 +119,18 @@ public final class FontConfig implements Parcelable { } /** + * Returns a locale fallback customizations. + * + * This field is used for creating the system fallback in the system server. This field is + * always empty in the application process. + * + * @hide + */ + public @NonNull List<Customization.LocaleFallback> getLocaleFallbackCustomizations() { + return mLocaleFallbackCustomizations; + } + + /** * Returns the last modified time in milliseconds. * * This is a value of {@link System#currentTimeMillis()} when the system font configuration was @@ -169,7 +187,9 @@ public final class FontConfig implements Parcelable { source.readTypedList(familyLists, NamedFamilyList.CREATOR); long lastModifiedDate = source.readLong(); int configVersion = source.readInt(); - return new FontConfig(families, aliases, familyLists, lastModifiedDate, configVersion); + return new FontConfig(families, aliases, familyLists, + Collections.emptyList(), // Don't need to pass customization to API caller. + lastModifiedDate, configVersion); } @Override @@ -813,4 +833,129 @@ public final class FontConfig implements Parcelable { + '}'; } } + + /** @hide */ + public static class Customization { + private Customization() {} // Singleton + + /** + * A class that represents customization of locale fallback + * + * This class represents a vendor customization of new-locale-family. + * + * <pre> + * <family customizationType="new-locale-family" operation="prepend" lang="ja-JP"> + * <font weight="400" style="normal">MyAlternativeFont.ttf + * <axis tag="wght" stylevalue="400"/> + * </font> + * </family> + * </pre> + * + * The operation can be one of prepend, replace or append. The operation prepend means that + * the new font family is inserted just before the original font family. The original font + * family is still in the fallback. The operation replace means that the original font + * family is replaced with new font family. The original font family is removed from the + * fallback. The operation append means that the new font family is inserted just after the + * original font family. The original font family is still in the fallback. + * + * The lang attribute is a BCP47 compliant language tag. The font fallback mainly uses ISO + * 15924 script code for matching. If the script code is missing, most likely script code + * will be used. + */ + public static class LocaleFallback { + private final Locale mLocale; + private final int mOperation; + private final FontFamily mFamily; + private final String mScript; + + public static final int OPERATION_PREPEND = 0; + public static final int OPERATION_APPEND = 1; + public static final int OPERATION_REPLACE = 2; + + /** @hide */ + @Retention(SOURCE) + @IntDef(prefix = { "OPERATION_" }, value = { + OPERATION_PREPEND, + OPERATION_APPEND, + OPERATION_REPLACE + }) + public @interface Operation {} + + + public LocaleFallback(@NonNull Locale locale, @Operation int operation, + @NonNull FontFamily family) { + mLocale = locale; + mOperation = operation; + mFamily = family; + mScript = resolveScript(locale); + } + + /** + * A customization target locale. + * @return a locale + */ + public @NonNull Locale getLocale() { + return mLocale; + } + + /** + * An operation to be applied to the original font family. + * + * The operation can be one of {@link #OPERATION_PREPEND}, {@link #OPERATION_REPLACE} or + * {@link #OPERATION_APPEND}. + * + * The operation prepend ({@link #OPERATION_PREPEND}) means that the new font family is + * inserted just before the original font family. The original font family is still in + * the fallback. + * + * The operation replace ({@link #OPERATION_REPLACE}) means that the original font + * family is replaced with new font family. The original font family is removed from the + * fallback. + * + * The operation append ({@link #OPERATION_APPEND}) means that the new font family is + * inserted just after the original font family. The original font family is still in + * the fallback. + * + * @return an operation. + */ + public @Operation int getOperation() { + return mOperation; + } + + /** + * Returns a family to be inserted or replaced to the fallback. + * + * @return a family + */ + public @NonNull FontFamily getFamily() { + return mFamily; + } + + /** + * Returns a script of the locale. If the script is missing in the given locale, the + * most likely locale is returned. + */ + public @NonNull String getScript() { + return mScript; + } + + @Override + public String toString() { + return "LocaleFallback{" + + "mLocale=" + mLocale + + ", mOperation=" + mOperation + + ", mFamily=" + mFamily + + '}'; + } + } + } + + /** @hide */ + public static String resolveScript(Locale locale) { + String script = locale.getScript(); + if (script != null && !script.isEmpty()) { + return script; + } + return ULocale.addLikelySubtags(ULocale.forLocale(locale)).getScript(); + } } diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java index c1d0e9b95b70..ac5eb3cbeeaa 100644 --- a/core/java/android/text/MeasuredParagraph.java +++ b/core/java/android/text/MeasuredParagraph.java @@ -16,6 +16,9 @@ package android.text; +import static com.android.text.flags.Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN; + +import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntRange; import android.annotation.NonNull; @@ -416,10 +419,12 @@ public class MeasuredParagraph { * @hide */ @TestApi + @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) public interface StyleRunCallback { /** * Called when a single style run is identified. */ + @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) void onAppendStyleRun(@NonNull Paint paint, @Nullable LineBreakConfig lineBreakConfig, @IntRange(from = 0) int length, boolean isRtl); @@ -427,6 +432,7 @@ public class MeasuredParagraph { /** * Called when a single replacement run is identified. */ + @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) void onAppendReplacementRun(@NonNull Paint paint, @IntRange(from = 0) int length, @Px @FloatRange(from = 0) float width); } @@ -488,6 +494,7 @@ public class MeasuredParagraph { @SuppressLint("ExecutorRegistration") @TestApi @NonNull + @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) public static MeasuredParagraph buildForStaticLayoutTest( @NonNull TextPaint paint, @Nullable LineBreakConfig lineBreakConfig, diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index e3c72c964d64..01279cea073f 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -16,6 +16,9 @@ package android.text; +import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH; + +import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntRange; import android.annotation.NonNull; @@ -439,6 +442,7 @@ public class StaticLayout extends Layout { * @see Layout.Builder#setUseBoundsForWidth(boolean) */ @NonNull + @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public Builder setUseBoundsForWidth(boolean useBoundsForWidth) { mUseBoundsForWidth = useBoundsForWidth; return this; diff --git a/core/java/android/text/flags/custom_locale_fallback.aconfig b/core/java/android/text/flags/custom_locale_fallback.aconfig new file mode 100644 index 000000000000..04e64f96454b --- /dev/null +++ b/core/java/android/text/flags/custom_locale_fallback.aconfig @@ -0,0 +1,8 @@ +package: "com.android.text.flags" + +flag { + name: "custom_locale_fallback" + namespace: "text" + description: "A feature flag that adds custom locale fallback to the vendor customization XML. This enables vendors to add their locale specific fonts, e.g. Japanese font." + bug: "" +} diff --git a/core/java/android/text/style/LineBreakConfigSpan.java b/core/java/android/text/style/LineBreakConfigSpan.java index 25c1db4d9804..682ffa180c0b 100644 --- a/core/java/android/text/style/LineBreakConfigSpan.java +++ b/core/java/android/text/style/LineBreakConfigSpan.java @@ -71,6 +71,10 @@ public class LineBreakConfigSpan { .setHyphenation(LineBreakConfig.HYPHENATION_DISABLED) .build(); + private static final LineBreakConfig sNoBreakConfig = new LineBreakConfig.Builder() + .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NO_BREAK) + .build(); + /** * A specialized {@link LineBreakConfigSpan} that used for preventing hyphenation. */ @@ -84,4 +88,24 @@ public class LineBreakConfigSpan { super(sNoHyphenationConfig); } } + + /** + * A specialized {@link LineBreakConfigSpan} that used for preventing line break. + * + * This is useful when you want to preserve some words in the same line. + * Note that even if this style is specified, the grapheme based line break is still performed + * for preventing clipping text. + * + * @see LineBreakConfigSpan + */ + @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) + public static final class NoBreakSpan extends LineBreakConfigSpan { + /** + * Construct a new {@link NoBreakSpan}. + */ + @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) + public NoBreakSpan() { + super(sNoBreakConfig); + } + } } diff --git a/core/java/android/view/IDecorViewGestureListener.aidl b/core/java/android/view/IDecorViewGestureListener.aidl new file mode 100644 index 000000000000..1022dbfb70eb --- /dev/null +++ b/core/java/android/view/IDecorViewGestureListener.aidl @@ -0,0 +1,32 @@ +/** + * 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 android.view; + +/** + * Listener for changes to gesture interception detector running at DecorView. + * + * {@hide} + */ +oneway interface IDecorViewGestureListener { + /** + * Called when a DecorView has started intercepting gesture. + * + * @param windowToken Where did this gesture interception result comes from. + * @param intercepted Whether the gesture interception detector has started interception. + */ + void onInterceptionChanged(in IBinder windowToken, in boolean intercepted); +} diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl index c4d307073d12..a150187bbc6c 100644 --- a/core/java/android/view/IRecentsAnimationController.aidl +++ b/core/java/android/view/IRecentsAnimationController.aidl @@ -23,6 +23,8 @@ import android.graphics.GraphicBuffer; import android.window.PictureInPictureSurfaceTransaction; import android.window.TaskSnapshot; +import com.android.internal.os.IResultReceiver; + /** * Passed to the {@link IRecentsAnimationRunner} in order for the runner to control to let the * runner control certain aspects of the recents animation, and to notify window manager when the @@ -58,7 +60,7 @@ interface IRecentsAnimationController { * top resumed app, false otherwise. */ @UnsupportedAppUsage - void finish(boolean moveHomeToTop, boolean sendUserLeaveHint); + void finish(boolean moveHomeToTop, boolean sendUserLeaveHint, in IResultReceiver finishCb); /** * Called by the handler to indicate that the recents animation input consumer should be diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index cccac95b9caa..c10fc9f9cb09 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -48,6 +48,7 @@ import android.view.IScrollCaptureResponseListener; import android.view.RemoteAnimationAdapter; import android.view.IRotationWatcher; import android.view.ISystemGestureExclusionListener; +import android.view.IDecorViewGestureListener; import android.view.IWallpaperVisibilityListener; import android.view.IWindow; import android.view.IWindowSession; @@ -1062,4 +1063,18 @@ interface IWindowManager @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + ".permission.ACCESS_SURFACE_FLINGER)") boolean replaceContentOnDisplay(int displayId, in SurfaceControl sc); + + /** + * Registers a DecorView gesture listener for a given display. + */ + @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + + ".permission.MONITOR_INPUT)") + void registerDecorViewGestureListener(IDecorViewGestureListener listener, int displayId); + + /** + * Unregisters a DecorView gesture listener for a given display. + */ + @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + + ".permission.MONITOR_INPUT)") + void unregisterDecorViewGestureListener(IDecorViewGestureListener listener, int displayId); } diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 83de2a0fafbe..7acf2f8ce06d 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -284,6 +284,11 @@ interface IWindowSession { oneway void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects); /** + * Called when the DecorView gesture interception state has changed. + */ + oneway void reportDecorViewGestureInterceptionChanged(IWindow window, in boolean intercepted); + + /** * Called when the keep-clear areas for this window have changed. */ oneway void reportKeepClearAreasChanged(IWindow window, in List<Rect> restricted, diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java index 2761aaeb4a7d..45b3fdd7e5bc 100644 --- a/core/java/android/view/InputWindowHandle.java +++ b/core/java/android/view/InputWindowHandle.java @@ -16,6 +16,8 @@ package android.view; +import static com.android.window.flags.Flags.surfaceTrustedOverlay; + import android.annotation.IntDef; import android.annotation.Nullable; import android.graphics.Matrix; @@ -35,7 +37,6 @@ import java.lang.ref.WeakReference; * @hide */ public final class InputWindowHandle { - /** * An internal annotation for all the {@link android.os.InputConfig} flags that can be * specified to {@link #inputConfig} to control the behavior of an input window. Only the @@ -59,7 +60,6 @@ public final class InputWindowHandle { InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER, InputConfig.IS_WALLPAPER, InputConfig.PAUSE_DISPATCHING, - InputConfig.TRUSTED_OVERLAY, InputConfig.WATCH_OUTSIDE_TOUCH, InputConfig.SLIPPERY, InputConfig.DISABLE_USER_ACTIVITY, @@ -272,4 +272,13 @@ public final class InputWindowHandle { } this.inputConfig &= ~inputConfig; } + + public void setTrustedOverlay(SurfaceControl.Transaction t, SurfaceControl sc, + boolean isTrusted) { + if (surfaceTrustedOverlay()) { + t.setTrustedOverlay(sc, isTrusted); + } else if (isTrusted) { + inputConfig |= InputConfig.TRUSTED_OVERLAY; + } + } } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index be6fb313b230..139c0bebedec 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -123,7 +123,8 @@ public final class SurfaceControl implements Parcelable { private static native long nativeMirrorSurface(long mirrorOfObject); private static native long nativeCreateTransaction(); private static native long nativeGetNativeTransactionFinalizer(); - private static native void nativeApplyTransaction(long transactionObj, boolean sync); + private static native void nativeApplyTransaction(long transactionObj, boolean sync, + boolean oneWay); private static native void nativeMergeTransaction(long transactionObj, long otherTransactionObj); private static native void nativeClearTransaction(long transactionObj); @@ -2785,10 +2786,22 @@ public final class SurfaceControl implements Parcelable { * as a new transaction. */ public void apply() { - apply(false); + apply(/*sync*/ false); } /** + * Applies the transaction as a one way binder call. This transaction will be applied out + * of order with other transactions that are applied synchronously. This method is not + * safe. It should only be used when the order does not matter. + * + * @hide + */ + public void applyAsyncUnsafe() { + apply(/*sync*/ false, /*oneWay*/ true); + } + + + /** * Clear the transaction object, without applying it. * * @hide @@ -2817,9 +2830,13 @@ public final class SurfaceControl implements Parcelable { * @hide */ public void apply(boolean sync) { + apply(sync, /*oneWay*/ false); + } + + private void apply(boolean sync, boolean oneWay) { applyResizedSurfaces(); notifyReparentedSurfaces(); - nativeApplyTransaction(mNativeObject, sync); + nativeApplyTransaction(mNativeObject, sync, oneWay); } /** @@ -4373,7 +4390,7 @@ public final class SurfaceControl implements Parcelable { void applyGlobalTransaction(boolean sync) { applyResizedSurfaces(); notifyReparentedSurfaces(); - nativeApplyTransaction(mNativeObject, sync); + nativeApplyTransaction(mNativeObject, sync, /*oneWay*/ false); } @Override diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index cf46bcccdf87..aa47f077226a 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -5320,6 +5320,29 @@ public final class ViewRootImpl implements ViewParent, } /** + * Called from DecorView when gesture interception state has changed. + * + * @param intercepted If DecorView is intercepting touch events + */ + public void updateDecorViewGestureInterception(boolean intercepted) { + mHandler.sendMessage( + mHandler.obtainMessage( + MSG_DECOR_VIEW_GESTURE_INTERCEPTION, + /* arg1= */ intercepted ? 1 : 0, + /* arg2= */ 0)); + } + + void decorViewInterceptionChanged(boolean intercepted) { + if (mView != null) { + try { + mWindowSession.reportDecorViewGestureInterceptionChanged(mWindow, intercepted); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** * Set the root-level system gesture exclusion rects. These are added to those provided by * the root's view hierarchy. */ @@ -5942,6 +5965,7 @@ public final class ViewRootImpl implements ViewParent, private static final int MSG_KEEP_CLEAR_RECTS_CHANGED = 35; private static final int MSG_REPORT_KEEP_CLEAR_RECTS = 36; private static final int MSG_PAUSED_FOR_SYNC_TIMEOUT = 37; + private static final int MSG_DECOR_VIEW_GESTURE_INTERCEPTION = 38; final class ViewRootHandler extends Handler { @Override @@ -6220,6 +6244,9 @@ public final class ViewRootImpl implements ViewParent, case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: { systemGestureExclusionChanged(); } break; + case MSG_DECOR_VIEW_GESTURE_INTERCEPTION: { + decorViewInterceptionChanged(/* intercepted= */ msg.arg1 == 1); + } break; case MSG_KEEP_CLEAR_RECTS_CHANGED: { keepClearRectsChanged(/* accessibilityFocusRectChanged= */ msg.arg1 == 1); } break; diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 8fe9b7bc0ca4..7c3b6ae42fcf 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -584,9 +584,13 @@ public class WindowlessWindowManager implements IWindowSession { } @Override - public void reportKeepClearAreasChanged(android.view.IWindow window, List<Rect> restrictedRects, - List<Rect> unrestrictedRects) { - } + public void reportDecorViewGestureInterceptionChanged(IWindow window, boolean intercepted) {} + + @Override + public void reportKeepClearAreasChanged( + android.view.IWindow window, + List<Rect> restrictedRects, + List<Rect> unrestrictedRects) {} @Override public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window, diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 89fa83e5c7aa..34e4c37de1b5 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -67,6 +67,7 @@ import android.os.SystemClock; import android.service.autofill.AutofillService; import android.service.autofill.FillCallback; import android.service.autofill.FillEventHistory; +import android.service.autofill.Flags; import android.service.autofill.IFillCallback; import android.service.autofill.UserData; import android.text.TextUtils; @@ -277,6 +278,12 @@ public final class AutofillManager { "android.view.autofill.extra.CLIENT_STATE"; /** + * @hide + */ + public static final String EXTRA_AUTH_STATE = + "android.view.autofill.extra.AUTH_STATE"; + + /** * Intent extra: the {@link android.view.inputmethod.InlineSuggestionsRequest} in the * autofill request. * @@ -428,6 +435,14 @@ public final class AutofillManager { public static final int STATE_UNKNOWN_FAILED = 6; /** + * Same as {@link #STATE_ACTIVE}, but when pending authentication after + * {@link AutofillManagerClient#authenticate(int, int, IntentSender, Intent, boolean)} + * + * @hide + */ + public static final int STATE_PENDING_AUTHENTICATION = 7; + + /** * Timeout in ms for calls to the field classification service. * @hide */ @@ -731,6 +746,10 @@ public final class AutofillManager { // Indicate whether WebView should always be included in the assist structure private boolean mShouldAlwaysIncludeWebviewInAssistStructure; + // Controls logic around apps changing some properties of their views when activity loses + // focus due to autofill showing biometric activity, password manager, or password breach check. + private boolean mRelayoutFix; + // Indicates whether called the showAutofillDialog() method. private boolean mShowAutofillDialogCalled = false; @@ -952,6 +971,8 @@ public final class AutofillManager { mShouldAlwaysIncludeWebviewInAssistStructure = AutofillFeatureFlags.shouldAlwaysIncludeWebviewInAssistStructure(); + + mRelayoutFix = Flags.relayout(); } /** @@ -1715,7 +1736,13 @@ public final class AutofillManager { synchronized (mLock) { if (mForAugmentedAutofillOnly) { if (sVerbose) { - Log.v(TAG, "notifyViewVisibilityChanged(): ignoring on augmented only mode"); + Log.v(TAG, "notifyViewVisibilityChanged(): ignoring on augmented only mode"); + } + return; + } + if (mRelayoutFix && mState == STATE_PENDING_AUTHENTICATION) { + if (sVerbose) { + Log.v(TAG, "notifyViewVisibilityChanged(): ignoring in auth pending mode"); } return; } @@ -2342,6 +2369,7 @@ public final class AutofillManager { if (!isActiveLocked()) { return; } + mState = STATE_ACTIVE; // If authenticate activity closes itself during onCreate(), there is no onStop/onStart // of app activity. We enforce enter event to re-show fill ui in such case. // CTS example: @@ -2830,6 +2858,9 @@ public final class AutofillManager { Intent fillInIntent, boolean authenticateInline) { synchronized (mLock) { if (sessionId == mSessionId) { + if (mRelayoutFix) { + mState = STATE_PENDING_AUTHENTICATION; + } final AutofillClient client = getClient(); if (client != null) { // clear mOnInvisibleCalled and we will see if receive onInvisibleForAutofill() @@ -3563,6 +3594,8 @@ public final class AutofillManager { return "UNKNOWN"; case STATE_ACTIVE: return "ACTIVE"; + case STATE_PENDING_AUTHENTICATION: + return "PENDING_AUTHENTICATION"; case STATE_FINISHED: return "FINISHED"; case STATE_SHOWING_SAVE_UI: @@ -3592,7 +3625,12 @@ public final class AutofillManager { @GuardedBy("mLock") private boolean isActiveLocked() { - return mState == STATE_ACTIVE; + return mState == STATE_ACTIVE || isPendingAuthenticationLocked(); + } + + @GuardedBy("mLock") + private boolean isPendingAuthenticationLocked() { + return mRelayoutFix && mState == STATE_PENDING_AUTHENTICATION; } @GuardedBy("mLock") diff --git a/core/java/android/view/flags/variable_refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig index 13a6f8d52dc6..56b5fac1c64a 100644 --- a/core/java/android/view/flags/variable_refresh_rate_flags.aconfig +++ b/core/java/android/view/flags/refresh_rate_flags.aconfig @@ -19,4 +19,11 @@ flag { namespace: "toolkit" description: "Feature flag for using expected presentation time of the Choreographer" bug: "278730197" +} + +flag { + name: "set_frame_rate_callback" + namespace: "core_graphics" + description: "Enable the `setFrameRate` callback" + bug: "299946220" }
\ No newline at end of file diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 26ceea6d1e4c..1fdd1a5a5a5f 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -80,6 +80,7 @@ import android.view.animation.LinearInterpolator; import android.view.autofill.AutofillId; import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.ContentCaptureSession; +import android.view.flags.Flags; import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CorrectionInfo; @@ -92,7 +93,6 @@ import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.SurroundingText; import android.view.inspector.InspectableProperty; import android.view.inspector.InspectableProperty.EnumEntry; -import android.widget.flags.Flags; import android.widget.RemoteViews.InteractionHandler; import com.android.internal.R; @@ -4518,7 +4518,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int overscrollMode = getOverScrollMode(); if (!trackMotionScroll(delta, delta)) { - if (Flags.platformWidgetHapticScrollFeedback()) { + if (Flags.scrollFeedbackApi()) { initHapticScrollFeedbackProviderIfNotExists(); mHapticScrollFeedbackProvider.onScrollProgress( event.getDeviceId(), event.getSource(), axis, delta); @@ -4534,7 +4534,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te float overscroll = (delta - (motionViewRealTop - motionViewPrevTop)) / ((float) getHeight()); boolean hitTopLimit = delta > 0; - if (Flags.platformWidgetHapticScrollFeedback()) { + if (Flags.scrollFeedbackApi()) { initHapticScrollFeedbackProviderIfNotExists(); mHapticScrollFeedbackProvider.onScrollLimit( event.getDeviceId(), event.getSource(), axis, diff --git a/core/java/android/widget/DifferentialMotionFlingHelper.java b/core/java/android/widget/DifferentialMotionFlingHelper.java index 95d24ec31209..ef01c3b79059 100644 --- a/core/java/android/widget/DifferentialMotionFlingHelper.java +++ b/core/java/android/widget/DifferentialMotionFlingHelper.java @@ -21,6 +21,8 @@ import android.content.Context; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; +import android.widget.flags.FeatureFlags; +import android.widget.flags.FeatureFlagsImpl; import com.android.internal.annotations.VisibleForTesting; @@ -50,6 +52,8 @@ public class DifferentialMotionFlingHelper { private final FlingVelocityThresholdCalculator mVelocityThresholdCalculator; private final DifferentialVelocityProvider mVelocityProvider; + private final FeatureFlags mWidgetFeatureFlags; + @Nullable private VelocityTracker mVelocityTracker; private float mLastFlingVelocity; @@ -134,7 +138,8 @@ public class DifferentialMotionFlingHelper { this(context, target, DifferentialMotionFlingHelper::calculateFlingVelocityThresholds, - DifferentialMotionFlingHelper::getCurrentVelocity); + DifferentialMotionFlingHelper::getCurrentVelocity, + /* widgetFeatureFlags= */ new FeatureFlagsImpl()); } @VisibleForTesting @@ -142,11 +147,13 @@ public class DifferentialMotionFlingHelper { Context context, DifferentialMotionFlingTarget target, FlingVelocityThresholdCalculator velocityThresholdCalculator, - DifferentialVelocityProvider velocityProvider) { + DifferentialVelocityProvider velocityProvider, + FeatureFlags widgetFeatureFlags) { mContext = context; mTarget = target; mVelocityThresholdCalculator = velocityThresholdCalculator; mVelocityProvider = velocityProvider; + mWidgetFeatureFlags = widgetFeatureFlags; } /** @@ -156,6 +163,9 @@ public class DifferentialMotionFlingHelper { * @param axis the axis being processed by the target View. */ public void onMotionEvent(MotionEvent event, int axis) { + if (!mWidgetFeatureFlags.enablePlatformWidgetDifferentialMotionFling()) { + return; + } boolean flingParamsChanged = calculateFlingVelocityThresholds(event, axis); if (mFlingVelocityThresholds[0] == Integer.MAX_VALUE) { // Integer.MAX_VALUE means that the device does not support fling for the current diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index e0e72ba1b9db..a1ebde76e98e 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -47,8 +47,8 @@ import android.view.ViewParent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AnimationUtils; +import android.view.flags.Flags; import android.view.inspector.InspectableProperty; -import android.widget.flags.Flags; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; @@ -1011,14 +1011,14 @@ public class ScrollView extends FrameLayout { if (newScrollY != oldScrollY) { super.scrollTo(mScrollX, newScrollY); if (hitLimit) { - if (Flags.platformWidgetHapticScrollFeedback()) { + if (Flags.scrollFeedbackApi()) { initHapticScrollFeedbackProviderIfNotExists(); mHapticScrollFeedbackProvider.onScrollLimit( event.getDeviceId(), event.getSource(), axis, /* isStart= */ newScrollY == 0); } } else { - if (Flags.platformWidgetHapticScrollFeedback()) { + if (Flags.scrollFeedbackApi()) { initHapticScrollFeedbackProviderIfNotExists(); mHapticScrollFeedbackProvider.onScrollProgress( event.getDeviceId(), event.getSource(), axis, delta); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 2c413300ef17..e8281eac5928 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -567,6 +567,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private float mShadowDy; private int mShadowColor; + private int mLastOrientation; + private boolean mPreDrawRegistered; private boolean mPreDrawListenerDetached; @@ -1193,6 +1195,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE; mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE; mJustificationMode = Layout.JUSTIFICATION_MODE_NONE; + mLastOrientation = getResources().getConfiguration().orientation; final Resources.Theme theme = context.getTheme(); @@ -4591,6 +4594,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mFontWeightAdjustment = newConfig.fontWeightAdjustment; setTypeface(getTypeface()); } + + InputMethodManager imm = getInputMethodManager(); + // if orientation changed and this TextView is currently served. + if (mLastOrientation != newConfig.orientation + && imm != null && imm.hasActiveInputConnection(this)) { + // EditorInfo.internalImeOptions are out of date. + imm.restartInput(this); + } + mLastOrientation = newConfig.orientation; } /** diff --git a/core/java/android/widget/flags/differential_motion_fling_flags.aconfig b/core/java/android/widget/flags/differential_motion_fling_flags.aconfig new file mode 100644 index 000000000000..79cfe566ac05 --- /dev/null +++ b/core/java/android/widget/flags/differential_motion_fling_flags.aconfig @@ -0,0 +1,8 @@ +package: "android.widget.flags" + +flag { + namespace: "toolkit" + name: "enable_platform_widget_differential_motion_fling" + description: "Enables differential motion fling in platform widgets" + bug: "293332089" +}
\ No newline at end of file diff --git a/core/java/android/widget/flags/scroll_view_flags.aconfig b/core/java/android/widget/flags/scroll_view_flags.aconfig deleted file mode 100644 index f93ade28750b..000000000000 --- a/core/java/android/widget/flags/scroll_view_flags.aconfig +++ /dev/null @@ -1,8 +0,0 @@ -package: "android.widget.flags" - -flag { - namespace: "widget" - name: "platform_widget_haptic_scroll_feedback" - description: "Enables haptic scroll feedback in platform widgets" - bug: "287914819" -}
\ No newline at end of file diff --git a/core/java/android/window/SystemPerformanceHinter.java b/core/java/android/window/SystemPerformanceHinter.java index b2c977bb1e57..e1a2b9485e13 100644 --- a/core/java/android/window/SystemPerformanceHinter.java +++ b/core/java/android/window/SystemPerformanceHinter.java @@ -17,6 +17,8 @@ package android.window; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; +import static android.view.Surface.FRAME_RATE_CATEGORY_DEFAULT; +import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH; import static android.view.SurfaceControl.FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN; import static android.view.SurfaceControl.FRAME_RATE_SELECTION_STRATEGY_SELF; @@ -29,8 +31,6 @@ import android.os.Trace; import android.util.Log; import android.view.SurfaceControl; -import com.android.internal.annotations.VisibleForTesting; - import java.io.PrintWriter; import java.util.ArrayList; import java.util.Random; @@ -148,7 +148,6 @@ public class SystemPerformanceHinter { * Constructor for the hinter. * @hide */ - @VisibleForTesting public SystemPerformanceHinter(@NonNull Context context, @Nullable DisplayRootProvider displayRootProvider, @Nullable Supplier<SurfaceControl.Transaction> transactionSupplier) { @@ -208,11 +207,14 @@ public class SystemPerformanceHinter { boolean transactionChanged = false; // Per-display flags if (nowEnabled(oldPerDisplayFlags, newPerDisplayFlags, HINT_SF_FRAME_RATE)) { - mTransaction.setFrameRateSelectionStrategy( - mDisplayRootProvider.getRootForDisplay(session.displayId), + SurfaceControl displaySurfaceControl = mDisplayRootProvider.getRootForDisplay( + session.displayId); + mTransaction.setFrameRateSelectionStrategy(displaySurfaceControl, FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN); + mTransaction.setFrameRateCategory(displaySurfaceControl, FRAME_RATE_CATEGORY_HIGH); transactionChanged = true; - Trace.beginAsyncSection("PerfHint-framerate-" + session.reason, session.traceCookie); + Trace.beginAsyncSection("PerfHint-framerate-" + session.displayId + "-" + + session.reason, session.traceCookie); } // Global flags @@ -226,7 +228,7 @@ public class SystemPerformanceHinter { Trace.beginAsyncSection("PerfHint-adpf-" + session.reason, session.traceCookie); } if (transactionChanged) { - mTransaction.apply(); + mTransaction.applyAsyncUnsafe(); } } @@ -245,9 +247,11 @@ public class SystemPerformanceHinter { boolean transactionChanged = false; // Per-display flags if (nowDisabled(oldPerDisplayFlags, newPerDisplayFlags, HINT_SF_FRAME_RATE)) { - mTransaction.setFrameRateSelectionStrategy( - mDisplayRootProvider.getRootForDisplay(session.displayId), + SurfaceControl displaySurfaceControl = mDisplayRootProvider.getRootForDisplay( + session.displayId); + mTransaction.setFrameRateSelectionStrategy(displaySurfaceControl, FRAME_RATE_SELECTION_STRATEGY_SELF); + mTransaction.setFrameRateCategory(displaySurfaceControl, FRAME_RATE_CATEGORY_DEFAULT); transactionChanged = true; Trace.endAsyncSection("PerfHint-framerate-" + session.reason, session.traceCookie); } @@ -263,7 +267,7 @@ public class SystemPerformanceHinter { Trace.endAsyncSection("PerfHint-adpf-" + session.reason, session.traceCookie); } if (transactionChanged) { - mTransaction.apply(); + mTransaction.applyAsyncUnsafe(); } } diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig new file mode 100644 index 000000000000..1b98806a0f01 --- /dev/null +++ b/core/java/android/window/flags/window_surfaces.aconfig @@ -0,0 +1,11 @@ +package: "com.android.window.flags" + +# Project link: https://gantry.corp.google.com/projects/android_platform_window_surfaces/changes + +flag { + namespace: "window_surfaces" + name: "surface_trusted_overlay" + description: "Whether to add trusted overlay flag on the SurfaceControl or the InputWindow" + is_fixed_read_only: true + bug: "292032926" +} diff --git a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java new file mode 100644 index 000000000000..e55c64199f45 --- /dev/null +++ b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java @@ -0,0 +1,56 @@ +/* + * 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 com.android.internal.display; + +import android.content.Context; +import android.hardware.display.DisplayManager; +import android.util.Log; +import android.view.Display; + +/** + * Constants and utility methods for refresh rate settings. + */ +public class RefreshRateSettingsUtils { + + private static final String TAG = "RefreshRateSettingsUtils"; + + public static final float DEFAULT_REFRESH_RATE = 60f; + + /** + * Find the highest refresh rate among all the modes of the default display. + * + * @param context The context + * @return The highest refresh rate + */ + public static float findHighestRefreshRateForDefaultDisplay(Context context) { + final DisplayManager dm = context.getSystemService(DisplayManager.class); + final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY); + + if (display == null) { + Log.w(TAG, "No valid default display device"); + return DEFAULT_REFRESH_RATE; + } + + float maxRefreshRate = DEFAULT_REFRESH_RATE; + for (Display.Mode mode : display.getSupportedModes()) { + if (mode.getRefreshRate() > maxRefreshRate) { + maxRefreshRate = mode.getRefreshRate(); + } + } + return maxRefreshRate; + } +} diff --git a/core/java/com/android/internal/foldables/OWNERS b/core/java/com/android/internal/foldables/OWNERS new file mode 100644 index 000000000000..6ce1ee4d3de2 --- /dev/null +++ b/core/java/com/android/internal/foldables/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/display/OWNERS diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 1be916f44f5b..85662634c22d 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -290,11 +290,12 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind }; private Consumer<Boolean> mCrossWindowBlurEnabledListener; + private final WearGestureInterceptionDetector mWearGestureInterceptionDetector; + DecorView(Context context, int featureId, PhoneWindow window, WindowManager.LayoutParams params) { super(context); mFeatureId = featureId; - mShowInterpolator = AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in); mHideInterpolator = AnimationUtils.loadInterpolator(context, @@ -314,6 +315,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind updateLogTag(params); mLegacyNavigationBarBackgroundPaint.setColor(Color.BLACK); + + mWearGestureInterceptionDetector = + WearGestureInterceptionDetector.isEnabled(context) + ? new WearGestureInterceptionDetector(context, this) + : null; } void setBackgroundFallback(@Nullable Drawable fallbackDrawable) { @@ -544,6 +550,18 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } } + ViewRootImpl viewRootImpl = getViewRootImpl(); + if (viewRootImpl != null && mWearGestureInterceptionDetector != null) { + boolean wasIntercepting = mWearGestureInterceptionDetector.isIntercepting(); + boolean intercepting = mWearGestureInterceptionDetector.onInterceptTouchEvent(event); + if (wasIntercepting != intercepting) { + viewRootImpl.updateDecorViewGestureInterception(intercepting); + } + if (intercepting) { + return true; + } + } + if (!SWEEP_OPEN_MENU) { return false; } diff --git a/core/java/com/android/internal/policy/WearGestureInterceptionDetector.java b/core/java/com/android/internal/policy/WearGestureInterceptionDetector.java new file mode 100644 index 000000000000..6fd50180e78b --- /dev/null +++ b/core/java/com/android/internal/policy/WearGestureInterceptionDetector.java @@ -0,0 +1,211 @@ +/* + * 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 com.android.internal.policy; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.TypedArray; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; + +/** + * Wear-specific gesture interception detector to be installed at DecorView, for compatibility of + * apps depending on legacy SwipeDismissLayout behavior. + * + * <p>Results of the detector will be used by {@code DecorView} to intercept motion events. The + * interception state will also be sent to {@code android.view.ViewRootImpl} and {@code + * com.android.server.wm.DisplayContent} through {@code android.view.IWindowSession}. + * + * <p>SystemUI can register {@code android.view.IDecorViewGestureListener} to listen for the result + * of the detector. The result will be valid for between a pair of touch down/up events. + */ +public class WearGestureInterceptionDetector { + private static final boolean DEBUG = false; + private static final String TAG = "WearGestureInterceptionDetector"; + + private final DecorView mInstalledDecorView; + private final float mTouchSlop; + private final float mSwipingStartThreshold; + private boolean mSwiping; + + private float mDownX; + private float mDownY; + private int mActivePointerId; + private boolean mDiscardIntercept; + + WearGestureInterceptionDetector(Context context, DecorView installedDecorView) { + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + mInstalledDecorView = installedDecorView; + mSwipingStartThreshold = mTouchSlop * 2; + } + + /** Check if this gesture interception detector should be enabled. */ + public static boolean isEnabled(Context context) { + PackageManager pm = context.getPackageManager(); + if (!pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) { + return false; + } + + // Compatibility check for flag that disables legacy SwipeDismissLayout. + TypedArray windowAttr = + context.obtainStyledAttributes(new int[] {android.R.attr.windowSwipeToDismiss}); + boolean windowSwipeToDismiss = true; + if (windowAttr.getIndexCount() > 0) { + windowSwipeToDismiss = windowAttr.getBoolean(0, true); + } + windowAttr.recycle(); + return windowSwipeToDismiss; + } + + private boolean isPointerIndexValid(MotionEvent ev) { + int pointerIndex = ev.findPointerIndex(mActivePointerId); + if (pointerIndex == -1) { + if (DEBUG) { + Log.e(TAG, "Invalid pointer index: ignoring."); + } + mDiscardIntercept = true; + return false; + } + return true; + } + + private void updateSwiping(MotionEvent ev) { + if (mSwiping) { + return; + } + float deltaX = ev.getRawX() - mDownX; + float deltaY = ev.getRawY() - mDownY; + // Check if we have left the touch slop area. + if ((deltaX * deltaX) + (deltaY * deltaY) > (mTouchSlop * mTouchSlop)) { + mSwiping = deltaX > mSwipingStartThreshold && Math.abs(deltaY) < Math.abs(deltaX); + } + } + + private void updateDiscardIntercept(MotionEvent ev) { + if (!mSwiping) { + // Don't look at canScroll until we have passed the touch slop + return; + } + if (mDiscardIntercept) { + return; + } + final boolean checkLeft = mDownX < ev.getRawX(); + final float x = ev.getX(mActivePointerId); + final float y = ev.getY(mActivePointerId); + if (canScroll(mInstalledDecorView, false, checkLeft, x, y)) { + mDiscardIntercept = true; + } + } + + /** Resets internal members when canceling. */ + private void resetMembers() { + mDownX = 0; + mDownY = 0; + mSwiping = false; + mDiscardIntercept = false; + } + + /** Should we intercept the MotionEvent for system gesture? */ + public boolean isIntercepting() { + return !mDiscardIntercept && mSwiping; + } + + /** Tests if the MotionEvent should be intercepted */ + public boolean onInterceptTouchEvent(MotionEvent ev) { + switch (ev.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + resetMembers(); + mDownX = ev.getRawX(); + mDownY = ev.getRawY(); + mActivePointerId = ev.getPointerId(0); + break; + case MotionEvent.ACTION_POINTER_DOWN: + mActivePointerId = ev.getPointerId(ev.getActionIndex()); + break; + case MotionEvent.ACTION_POINTER_UP: + int associatedPointerIndex = ev.getActionIndex(); + if (ev.getPointerId(associatedPointerIndex) == mActivePointerId) { + // This was our active pointer going up. + // Choose the first available pointer index. + int newActionIndex = associatedPointerIndex == 0 ? 1 : 0; + mActivePointerId = ev.getPointerId(newActionIndex); + } + break; + case MotionEvent.ACTION_MOVE: + if (mDiscardIntercept) { + break; + } + if (!isPointerIndexValid(ev)) { + break; + } + updateSwiping(ev); + updateDiscardIntercept(ev); + break; + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + resetMembers(); + break; + } + return isIntercepting(); + } + + /** + * Tests scroll-ability within child views of v in the direction of dx. + * + * @param v View to test for horizontal scroll-ability + * @param checkSelf Whether the view v passed should itself be checked for scroll-ability + * (true), or just its children (false). + * @param checkLeft Which direction to check? Left = true, right = false. + * @param x X coordinate of the active touch point + * @param y Y coordinate of the active touch point + * @return true if child views of v can be scrolled by delta of dx. + */ + private boolean canScroll(View v, boolean checkSelf, boolean checkLeft, float x, float y) { + if (v instanceof ViewGroup) { + final ViewGroup group = (ViewGroup) v; + final int scrollX = v.getScrollX(); + final int scrollY = v.getScrollY(); + final int count = group.getChildCount(); + for (int i = count - 1; i >= 0; i--) { + final View child = group.getChildAt(i); + + if (x + scrollX < child.getLeft() + || x + scrollX >= child.getRight() + || y + scrollY < child.getTop() + || y + scrollY >= child.getBottom()) { + // This child is out of bound, don't bother checking. + continue; + } + + // Recursively check until finding the first scrollable or none is scrollable. + if (canScroll( + /* view= */ child, + /* checkSelf= */ true, + /* checkLeft= */ checkLeft, + /* x= */ x + scrollX - child.getLeft(), + /* y= */ y + scrollY - child.getTop())) { + return true; + } + } + } + + return checkSelf && v.canScrollHorizontally(checkLeft ? -1 : 1); + } +} diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 9384f41e26f5..f79dbe761e07 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -469,9 +469,10 @@ static void nativeSetDefaultBufferSize(JNIEnv* env, jclass clazz, jlong nativeOb } } -static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) { +static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync, + jboolean oneWay) { auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); - transaction->apply(sync); + transaction->apply(sync, oneWay); } static void nativeMergeTransaction(JNIEnv* env, jclass clazz, @@ -2119,7 +2120,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetDefaultBufferSize}, {"nativeCreateTransaction", "()J", (void*)nativeCreateTransaction }, - {"nativeApplyTransaction", "(JZ)V", + {"nativeApplyTransaction", "(JZZ)V", (void*)nativeApplyTransaction }, {"nativeGetNativeTransactionFinalizer", "()J", (void*)nativeGetNativeTransactionFinalizer }, diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index 6c936801de18..473270229bdb 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -98,6 +98,7 @@ message SecureSettingsProto { // Settings for font scaling optional SettingProto accessibility_font_scaling_has_been_changed = 51 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto accessibility_force_invert_color_enabled = 52 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_magnification_gesture = 53 [ (android.privacy).dest = DEST_AUTOMATIC ]; } optional Accessibility accessibility = 2; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index e34e42317c0c..a0b8cca58d9b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -48,6 +48,7 @@ <protected-broadcast android:name="android.intent.action.CANCEL_ENABLE_ROLLBACK" /> <protected-broadcast android:name="android.intent.action.ROLLBACK_COMMITTED" /> <protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" /> + <protected-broadcast android:name="android.intent.action.PACKAGE_UNSTOPPED" /> <protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" /> <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" /> <protected-broadcast android:name="android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION" /> @@ -7232,6 +7233,13 @@ android:description="@string/permdesc_fullScreenIntent" android:protectionLevel="normal|appop" /> + <!-- Required for the assistant apps targeting {@link android.os.Build.VERSION_CODES#V} + that receive voice trigger from the trusted hotword detection service. + <p>Protection level: signature|privileged|appop + @hide --> + <permission android:name="android.permission.RECEIVE_SANDBOX_TRIGGER_AUDIO" + android:protectionLevel="signature|privileged|appop" /> + <!-- @SystemApi Allows requesting the framework broadcast the {@link Intent#ACTION_DEVICE_CUSTOMIZATION_READY} intent. @hide --> diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml index 8b6c90141bb7..27f8138ac5e3 100644 --- a/core/res/res/layout/autofill_save.xml +++ b/core/res/res/layout/autofill_save.xml @@ -60,10 +60,11 @@ android:gravity="center" android:textAppearance="@style/AutofillSaveUiTitle"> </TextView> - <LinearLayout + <FrameLayout android:id="@+id/autofill_save_custom_subtitle" android:layout_width="match_parent" android:layout_height="wrap_content" + android:minHeight="0dp" android:visibility="gone"/> </LinearLayout> diff --git a/core/res/res/values-watch/dimens_material.xml b/core/res/res/values-watch/dimens_material.xml index 2ab2d91058e2..8becb0880f97 100644 --- a/core/res/res/values-watch/dimens_material.xml +++ b/core/res/res/values-watch/dimens_material.xml @@ -47,11 +47,12 @@ <dimen name="progress_bar_height">24dp</dimen> <!-- Progress bar message dimens --> - <dimen name="message_progress_dialog_text_size">18sp</dimen> + <dimen name="message_progress_dialog_text_size">14sp</dimen> <dimen name="message_progress_dialog_bottom_padding">80px</dimen> <dimen name="message_progress_dialog_top_padding">0dp</dimen> <dimen name="message_progress_dialog_start_padding">0dp</dimen> <dimen name="message_progress_dialog_end_padding">0dp</dimen> + <item name="message_progress_dialog_letter_spacing" format="float" type="dimen">0.021</item> <!-- fallback for screen percentage widths --> <dimen name="screen_percentage_05">0dp</dimen> diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml index 8698e86ba5f9..f3e412dc948e 100644 --- a/core/res/res/values-watch/styles_material.xml +++ b/core/res/res/values-watch/styles_material.xml @@ -100,7 +100,9 @@ please see styles_device_defaults.xml. <style name="ProgressDialogMessage"> <item name="android:textAlignment">center</item> - <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item> + <item name="android:fontFamily">google-sans-text</item> + <item name="android:letterSpacing">@dimen/message_progress_dialog_letter_spacing</item> + <item name="textColor">?attr/textColorPrimary</item> <item name="textSize">@dimen/message_progress_dialog_text_size</item> <item name="paddingBottom">@dimen/message_progress_dialog_bottom_padding</item> <item name="paddingEnd">@dimen/message_progress_dialog_end_padding</item> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 4360c5ae3dc0..7ef81abb8f0d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1151,6 +1151,14 @@ <!-- Allows activities to be launched on a long press on power during device setup. --> <bool name="config_allowStartActivityForLongPressOnPowerInSetup">false</bool> + <!-- Control the behavior when the user short presses the settings button. + 0 - Nothing + 1 - Launch notification panel + This needs to match the constants in + com/android/server/policy/PhoneWindowManager.java + --> + <integer name="config_shortPressOnSettingsBehavior">0</integer> + <!-- Control the behavior when the user short presses the power button. 0 - Nothing 1 - Go to sleep (doze) diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 7f3069542306..643f4b148d74 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1816,6 +1816,7 @@ <java-symbol type="integer" name="config_lidNavigationAccessibility" /> <java-symbol type="integer" name="config_lidOpenRotation" /> <java-symbol type="integer" name="config_longPressOnHomeBehavior" /> + <java-symbol type="integer" name="config_shortPressOnSettingsBehavior" /> <java-symbol type="layout" name="global_actions" /> <java-symbol type="layout" name="global_actions_item" /> <java-symbol type="layout" name="global_actions_silent_mode" /> diff --git a/core/tests/BroadcastRadioTests/Android.bp b/core/tests/BroadcastRadioTests/Android.bp index 85d54e02d318..054d10c336e6 100644 --- a/core/tests/BroadcastRadioTests/Android.bp +++ b/core/tests/BroadcastRadioTests/Android.bp @@ -38,7 +38,7 @@ android_test { static_libs: [ "services.core", "androidx.test.rules", - "truth-prebuilt", + "truth", "testng", "mockito-target-extended", ], diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java index a1952282dd0b..824f5910f96c 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java @@ -16,20 +16,20 @@ package com.android.server.broadcastradio.aidl; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.after; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.timeout; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static org.junit.Assert.assertThrows; -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.doAnswer; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.app.compat.CompatChanges; import android.graphics.Bitmap; @@ -81,8 +81,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { private static final int USER_ID_1 = 11; private static final int USER_ID_2 = 12; - private static final VerificationWithTimeout CALLBACK_TIMEOUT = - timeout(/* millis= */ 200); + private static final int CALLBACK_TIMEOUT_MS = 200; + private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(CALLBACK_TIMEOUT_MS); private static final int SIGNAL_QUALITY = 90; private static final long AM_FM_FREQUENCY_SPACING = 500; private static final long[] AM_FM_FREQUENCY_LIST = {97_500, 98_100, 99_100}; @@ -166,12 +166,12 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { @Before public void setup() throws Exception { - when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); doReturn(true).when(() -> CompatChanges.isChangeEnabled( eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt())); + doReturn(USER_ID_1).when(mUserHandleMock).getIdentifier(); + doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser()); - doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); mRadioModule = new RadioModule(mBroadcastRadioMock, AidlTestUtils.makeDefaultModuleProperties()); @@ -222,7 +222,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { return Result.OK; }).when(mBroadcastRadioMock).seek(anyBoolean(), anyBoolean()); - when(mBroadcastRadioMock.getImage(anyInt())).thenReturn(null); + doReturn(null).when(mBroadcastRadioMock).getImage(anyInt()); doAnswer(invocation -> { int configFlag = (int) invocation.getArguments()[0]; @@ -275,7 +275,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { mTunerSessions[0].setConfiguration(FM_BAND_CONFIG); - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) .onConfigurationChanged(FM_BAND_CONFIG); } @@ -446,26 +446,11 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { mTunerSessions[0].tune(initialSel); - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) .onCurrentProgramInfoChanged(tuneInfo); } @Test - public void tune_forSystemUser() throws Exception { - when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM); - doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); - doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); - ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); - RadioManager.ProgramInfo tuneInfo = - AidlTestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY); - openAidlClients(/* numClients= */ 1); - - mTunerSessions[0].tune(initialSel); - - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo); - } - - @Test public void tune_withUnknownErrorFromHal_fails() throws Exception { openAidlClients(/* numClients= */ 1); ProgramSelector sel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); @@ -525,7 +510,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false); - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) .onCurrentProgramInfoChanged(any()); } @@ -604,7 +589,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false); - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) .onCurrentProgramInfoChanged(seekUpInfo); } @@ -638,6 +623,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { openAidlClients(/* numClients= */ 1); ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); mTunerSessions[0].tune(initialSel); + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(any()); doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); mTunerSessions[0].cancel(); @@ -686,8 +672,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { public void getImage_whenHalThrowsException_fails() throws Exception { openAidlClients(/* numClients= */ 1); String exceptionMessage = "HAL service died."; - when(mBroadcastRadioMock.getImage(anyInt())) - .thenThrow(new RemoteException(exceptionMessage)); + doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock) + .getImage(anyInt()); RuntimeException thrown = assertThrows(RuntimeException.class, () -> { mTunerSessions[0].getImage(/* id= */ 1); @@ -713,7 +699,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { mTunerSessions[0].startBackgroundScan(); - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onBackgroundScanComplete(); + verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) + .onBackgroundScanComplete(); } @Test @@ -905,7 +892,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false, /* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>())); - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onProgramListUpdated(any()); + verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) + .onProgramListUpdated(any()); } @Test @@ -1160,8 +1148,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { Map<String, String> parametersSet = Map.of("mockParam1", "mockValue1", "mockParam2", "mockValue2"); String exceptionMessage = "HAL service died."; - when(mBroadcastRadioMock.setParameters(any())) - .thenThrow(new RemoteException(exceptionMessage)); + doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock) + .setParameters(any()); RuntimeException thrown = assertThrows(RuntimeException.class, () -> { mTunerSessions[0].setParameters(parametersSet); @@ -1186,8 +1174,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { openAidlClients(/* numClients= */ 1); List<String> parameterKeys = List.of("mockKey1", "mockKey2"); String exceptionMessage = "HAL service died."; - when(mBroadcastRadioMock.getParameters(any())) - .thenThrow(new RemoteException(exceptionMessage)); + doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock) + .getParameters(any()); RuntimeException thrown = assertThrows(RuntimeException.class, () -> { mTunerSessions[0].getParameters(parameterKeys); @@ -1198,7 +1186,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test - public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback() + public void onCurrentProgramInfoChanged_withNonCurrentUser_doesNotInvokeCallback() throws Exception { openAidlClients(1); doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser()); @@ -1206,7 +1194,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { mHalTunerCallback.onCurrentProgramInfoChanged(AidlTestUtils.makeHalProgramInfo( AidlTestUtils.makeHalFmSelector(AM_FM_FREQUENCY_LIST[1]), SIGNAL_QUALITY)); - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) .onCurrentProgramInfoChanged(any()); } diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java index fac9eaafe94c..3ec44d14b409 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java @@ -16,22 +16,22 @@ package com.android.server.broadcastradio.hal2; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.after; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.timeout; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertThrows; -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.doAnswer; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.graphics.Bitmap; import android.hardware.broadcastradio.V2_0.Constants; @@ -78,8 +78,8 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { private static final int USER_ID_1 = 11; private static final int USER_ID_2 = 12; - private static final VerificationWithTimeout CALLBACK_TIMEOUT = - timeout(/* millis= */ 200); + private static final int CALLBACK_TIMEOUT_MS = 200; + private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(CALLBACK_TIMEOUT_MS); private static final int SIGNAL_QUALITY = 1; private static final long AM_FM_FREQUENCY_SPACING = 500; private static final long[] AM_FM_FREQUENCY_LIST = {97_500, 98_100, 99_100}; @@ -113,7 +113,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { @Before public void setup() throws Exception { - when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); + doReturn(USER_ID_1).when(mUserHandleMock).getIdentifier(); doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser()); @@ -170,7 +170,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { return Result.OK; }).when(mHalTunerSessionMock).scan(anyBoolean(), anyBoolean()); - when(mBroadcastRadioMock.getImage(anyInt())).thenReturn(new ArrayList<Byte>(0)); + doReturn(new ArrayList<Byte>(0)).when(mBroadcastRadioMock).getImage(anyInt()); doAnswer(invocation -> { int configFlag = (int) invocation.getArguments()[0]; @@ -227,7 +227,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { mTunerSessions[0].setConfiguration(FM_BAND_CONFIG); - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) .onConfigurationChanged(FM_BAND_CONFIG); } @@ -379,7 +379,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { mTunerSessions[0].tune(initialSel); - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) .onCurrentProgramInfoChanged(tuneInfo); } @@ -398,20 +398,6 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { } @Test - public void tune_forSystemUser() throws Exception { - when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM); - doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); - doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); - ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); - RadioManager.ProgramInfo tuneInfo = TestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY); - openAidlClients(/* numClients= */ 1); - - mTunerSessions[0].tune(initialSel); - - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo); - } - - @Test public void step_withDirectionUp() throws Exception { long initFreq = AM_FM_FREQUENCY_LIST[1]; ProgramSelector initialSel = TestUtils.makeFmSelector(initFreq); @@ -455,7 +441,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false); - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) .onCurrentProgramInfoChanged(any()); } @@ -533,7 +519,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false); - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) .onCurrentProgramInfoChanged(seekUpInfo); } @@ -563,22 +549,11 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { } @Test - public void cancel_forNonCurrentUser() throws Exception { - openAidlClients(/* numClients= */ 1); - ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); - mTunerSessions[0].tune(initialSel); - doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); - - mTunerSessions[0].cancel(); - - verify(mHalTunerSessionMock, never()).cancel(); - } - - @Test public void cancel_forNonCurrentUser_doesNotCancel() throws Exception { openAidlClients(/* numClients= */ 1); ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); mTunerSessions[0].tune(initialSel); + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(any()); doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); mTunerSessions[0].cancel(); @@ -627,8 +602,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { public void getImage_whenHalThrowsException_fails() throws Exception { openAidlClients(/* numClients= */ 1); String exceptionMessage = "HAL service died."; - when(mBroadcastRadioMock.getImage(anyInt())) - .thenThrow(new RemoteException(exceptionMessage)); + doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock).getImage(anyInt()); RuntimeException thrown = assertThrows(RuntimeException.class, () -> { mTunerSessions[0].getImage(/* id= */ 1); @@ -654,7 +628,8 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { mTunerSessions[0].startBackgroundScan(); - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onBackgroundScanComplete(); + verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) + .onBackgroundScanComplete(); } @Test @@ -845,8 +820,8 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { Map<String, String> parametersSet = Map.of("mockParam1", "mockValue1", "mockParam2", "mockValue2"); String exceptionMessage = "HAL service died."; - when(mHalTunerSessionMock.setParameters(any())) - .thenThrow(new RemoteException(exceptionMessage)); + doThrow(new RemoteException(exceptionMessage)).when(mHalTunerSessionMock) + .setParameters(any()); RuntimeException thrown = assertThrows(RuntimeException.class, () -> { mTunerSessions[0].setParameters(parametersSet); @@ -871,8 +846,8 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { openAidlClients(/* numClients= */ 1); List<String> parameterKeys = List.of("mockKey1", "mockKey2"); String exceptionMessage = "HAL service died."; - when(mHalTunerSessionMock.getParameters(any())) - .thenThrow(new RemoteException(exceptionMessage)); + doThrow(new RemoteException(exceptionMessage)).when(mHalTunerSessionMock) + .getParameters(any()); RuntimeException thrown = assertThrows(RuntimeException.class, () -> { mTunerSessions[0].getParameters(parameterKeys); @@ -883,7 +858,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { } @Test - public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback() + public void onCurrentProgramInfoChanged_withNonCurrentUser_doesNotInvokeCallback() throws Exception { openAidlClients(1); doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser()); @@ -891,7 +866,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { mHalTunerCallback.onCurrentProgramInfoChanged(TestUtils.makeHalProgramInfo( TestUtils.makeHalFmSelector(/* freq= */ 97300), SIGNAL_QUALITY)); - verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) .onCurrentProgramInfoChanged(any()); } diff --git a/core/tests/GameManagerTests/Android.bp b/core/tests/GameManagerTests/Android.bp index 8c5d6d5a76a1..0e3bc6562edb 100644 --- a/core/tests/GameManagerTests/Android.bp +++ b/core/tests/GameManagerTests/Android.bp @@ -30,7 +30,7 @@ android_test { "frameworks-base-testutils", "junit", "platform-test-annotations", - "truth-prebuilt", + "truth", ], libs: ["android.test.runner"], platform_apis: true, diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp index 6f2366e32574..b631df1fcf57 100644 --- a/core/tests/PackageInstallerSessions/Android.bp +++ b/core/tests/PackageInstallerSessions/Android.bp @@ -35,7 +35,7 @@ android_test { "frameworks-base-testutils", "platform-test-annotations", "testng", - "truth-prebuilt", + "truth", ], libs: [ diff --git a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp index 52608351775c..1fb5f2c0789b 100644 --- a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp +++ b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp @@ -18,7 +18,7 @@ android_test { "platform-test-annotations", "platformprotosnano", "statsdprotolite", - "truth-prebuilt", + "truth", ], libs: ["android.test.runner"], diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp index 2b34ee2646f3..7c1ac487bfdb 100644 --- a/core/tests/bugreports/Android.bp +++ b/core/tests/bugreports/Android.bp @@ -32,7 +32,7 @@ android_test { static_libs: [ "androidx.test.rules", "androidx.test.uiautomator_uiautomator", - "truth-prebuilt", + "truth", ], test_suites: ["general-tests"], sdk_version: "test_current", diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 04622fda75df..2993a0e63228 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -58,12 +58,13 @@ android_test { "androidx.test.uiautomator_uiautomator", "platform-test-annotations", "platform-compat-test-rules", - "truth-prebuilt", + "truth", "print-test-util-lib", "testng", "servicestests-utils", "device-time-shell-utils", "testables", + "com.android.text.flags-aconfig-java", ], libs: [ @@ -149,7 +150,7 @@ android_library { "androidx.test.runner", "androidx.test.rules", "mockito-target-minus-junit4", - "truth-prebuilt", + "truth", ], libs: [ diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java index a8a5059eea20..3f78396e3a70 100644 --- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java +++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java @@ -16,6 +16,8 @@ package android.graphics; +import static com.android.text.flags.Flags.FLAG_CUSTOM_LOCALE_FALLBACK; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -30,6 +32,9 @@ import android.graphics.fonts.FontFamily; import android.graphics.fonts.SystemFonts; import android.graphics.text.PositionedGlyphs; import android.graphics.text.TextRunShaper; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.text.FontConfig; import android.util.ArrayMap; @@ -39,6 +44,7 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.xmlpull.v1.XmlPullParserException; @@ -107,6 +113,10 @@ public class TypefaceSystemFallbackTest { GLYPH_2EM_WIDTH = paint.measureText("a"); } + @Rule + public final CheckFlagsRule mCheckFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule(); + @Before public void setUp() { final AssetManager am = @@ -877,6 +887,130 @@ public class TypefaceSystemFallbackTest { assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); } + private static void assertA3emFontIsUsed(Typeface typeface) { + final Paint paint = new Paint(); + assertNotNull(typeface); + paint.setTypeface(typeface); + assertTrue("a3em font must be used", GLYPH_3EM_WIDTH == paint.measureText("a") + && GLYPH_1EM_WIDTH == paint.measureText("b") + && GLYPH_1EM_WIDTH == paint.measureText("c")); + } + + private static void assertB3emFontIsUsed(Typeface typeface) { + final Paint paint = new Paint(); + assertNotNull(typeface); + paint.setTypeface(typeface); + assertTrue("b3em font must be used", GLYPH_1EM_WIDTH == paint.measureText("a") + && GLYPH_3EM_WIDTH == paint.measureText("b") + && GLYPH_1EM_WIDTH == paint.measureText("c")); + } + + private static String getBaseXml(String font, String lang) { + final String xml = "<?xml version='1.0' encoding='UTF-8'?>" + + "<familyset>" + + " <family>" + + " <font weight='400' style='normal'>no_coverage.ttf</font>" + + " </family>" + + " <family name='named-family'>" + + " <font weight='400' style='normal'>no_coverage.ttf</font>" + + " </family>" + + " <family lang='%s'>" + + " <font weight='400' style='normal'>%s</font>" + + " </family>" + + "</familyset>"; + return String.format(xml, lang, font); + } + + private static String getCustomizationXml(String font, String op, String lang) { + final String xml = "<?xml version='1.0' encoding='UTF-8'?>" + + "<fonts-modification version='1'>" + + " <family customizationType='new-locale-family' operation='%s' lang='%s'>" + + " <font weight='400' style='normal' fallbackFor='named-family'>%s</font>" + + " </family>" + + "</fonts-modification>"; + return String.format(xml, op, lang, font); + } + + @RequiresFlagsEnabled(FLAG_CUSTOM_LOCALE_FALLBACK) + @Test + public void testBuildSystemFallback__Customization_locale_prepend() { + final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); + final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); + + buildSystemFallback( + getBaseXml("a3em.ttf", "ja-JP"), + getCustomizationXml("b3em.ttf", "prepend", "ja-JP"), + fontMap, fallbackMap); + Typeface typeface = fontMap.get("named-family"); + + // operation "prepend" places font before the original font, thus b3em is used. + assertB3emFontIsUsed(typeface); + } + + @RequiresFlagsEnabled(FLAG_CUSTOM_LOCALE_FALLBACK) + @Test + public void testBuildSystemFallback__Customization_locale_replace() { + final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); + final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); + + buildSystemFallback( + getBaseXml("a3em.ttf", "ja-JP"), + getCustomizationXml("b3em.ttf", "replace", "ja-JP"), + fontMap, fallbackMap); + Typeface typeface = fontMap.get("named-family"); + + // operation "replace" removes the original font, thus b3em font is used. + assertB3emFontIsUsed(typeface); + } + + @RequiresFlagsEnabled(FLAG_CUSTOM_LOCALE_FALLBACK) + @Test + public void testBuildSystemFallback__Customization_locale_append() { + final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); + final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); + + buildSystemFallback( + getBaseXml("a3em.ttf", "ja-JP"), + getCustomizationXml("b3em.ttf", "append", "ja-JP"), + fontMap, fallbackMap); + Typeface typeface = fontMap.get("named-family"); + + // operation "append" comes next to the original font, so the original "a3em" is used. + assertA3emFontIsUsed(typeface); + } + + @RequiresFlagsEnabled(FLAG_CUSTOM_LOCALE_FALLBACK) + @Test + public void testBuildSystemFallback__Customization_locale_ScriptMismatch() { + final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); + final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); + + buildSystemFallback( + getBaseXml("a3em.ttf", "ja-JP"), + getCustomizationXml("b3em.ttf", "replace", "ko-KR"), + fontMap, fallbackMap); + Typeface typeface = fontMap.get("named-family"); + + // Since the script doesn't match, the customization is ignored. + assertA3emFontIsUsed(typeface); + } + + @RequiresFlagsEnabled(FLAG_CUSTOM_LOCALE_FALLBACK) + @Test + public void testBuildSystemFallback__Customization_locale_SubscriptMatch() { + final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); + final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); + + buildSystemFallback( + getBaseXml("a3em.ttf", "ja-JP"), + getCustomizationXml("b3em.ttf", "replace", "ko-Hani-KR"), + fontMap, fallbackMap); + Typeface typeface = fontMap.get("named-family"); + + // Hani script is supported by Japanese, Jpan. + assertB3emFontIsUsed(typeface); + } + @Test(expected = IllegalArgumentException.class) public void testBuildSystemFallback__Customization_new_named_family_no_name_exception() { final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>" @@ -902,7 +1036,6 @@ public class TypefaceSystemFallbackTest { readFontCustomization(oemXml); } - @Test public void testBuildSystemFallback_UpdatableFont() { final String xml = "<?xml version='1.0' encoding='UTF-8'?>" diff --git a/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java b/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java index 55ded9c8813d..bfdb15b7f7c8 100644 --- a/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java +++ b/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java @@ -16,6 +16,10 @@ package android.service.notification; +import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; +import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL; +import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE; + import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM; import static junit.framework.Assert.assertEquals; @@ -24,20 +28,38 @@ import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertNotEquals; +import static org.mockito.Mockito.spy; + +import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.ShortcutInfo; +import android.os.Bundle; import android.os.Parcel; +import android.os.SharedMemory; +import android.testing.TestableContext; +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags; 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.junit.runners.Parameterized; +import java.util.ArrayList; +import java.util.List; + @SmallTest @RunWith(Parameterized.class) public class NotificationRankingUpdateTest { @@ -56,6 +78,345 @@ public class NotificationRankingUpdateTest { @Parameterized.Parameter public boolean mRankingUpdateAshmem; + @Rule + public TestableContext mContext = + spy(new TestableContext(InstrumentationRegistry.getContext(), null)); + + protected TestableContext getContext() { + return mContext; + } + + public static String[] mKeys = new String[] { "key", "key1", "key2", "key3", "key4"}; + + /** + * Creates a NotificationRankingUpdate with prepopulated Ranking entries + * @param context A testable context, used for PendingIntent creation + * @return The NotificationRankingUpdate to be used as test data + */ + public static NotificationRankingUpdate generateUpdate(TestableContext context) { + NotificationListenerService.Ranking[] rankings = + new NotificationListenerService.Ranking[mKeys.length]; + for (int i = 0; i < mKeys.length; i++) { + final String key = mKeys[i]; + NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking(); + ranking.populate( + key, + i, + !isIntercepted(i), + getVisibilityOverride(i), + getSuppressedVisualEffects(i), + getImportance(i), + getExplanation(key), + getOverrideGroupKey(key), + getChannel(key, i), + getPeople(key, i), + getSnoozeCriteria(key, i), + getShowBadge(i), + getUserSentiment(i), + getHidden(i), + lastAudiblyAlerted(i), + getNoisy(i), + getSmartActions(key, i, context), + getSmartReplies(key, i), + canBubble(i), + isTextChanged(i), + isConversation(i), + getShortcutInfo(i), + getRankingAdjustment(i), + isBubble(i), + getProposedImportance(i), + hasSensitiveContent(i) + ); + rankings[i] = ranking; + } + return new NotificationRankingUpdate(rankings); + } + + /** + * Produces a visibility override value based on the provided index. + */ + public static int getVisibilityOverride(int index) { + return index * 9; + } + + /** + * Produces a group key based on the provided key. + */ + public static String getOverrideGroupKey(String key) { + return key + key; + } + + /** + * Produces a boolean that can be used to represent isIntercepted, based on the provided index. + */ + public static boolean isIntercepted(int index) { + return index % 2 == 0; + } + + /** + * Produces a suppressed visual effects value based on the provided index + */ + public static int getSuppressedVisualEffects(int index) { + return index * 2; + } + + /** + * Produces an importance value, based on the provided index + */ + public static int getImportance(int index) { + return index; + } + + /** + * Produces an explanation value, based on the provided key + */ + public static String getExplanation(String key) { + return key + "explain"; + } + + /** + * Produces a notification channel, based on the provided key and index + */ + public static NotificationChannel getChannel(String key, int index) { + return new NotificationChannel(key, key, getImportance(index)); + } + + /** + * Produces a boolean that can be used to represent showBadge, based on the provided index + */ + public static boolean getShowBadge(int index) { + return index % 3 == 0; + } + + /** + * Produces a user sentiment value, based on the provided index + */ + public static int getUserSentiment(int index) { + switch(index % 3) { + case 0: + return USER_SENTIMENT_NEGATIVE; + case 1: + return USER_SENTIMENT_NEUTRAL; + case 2: + return USER_SENTIMENT_POSITIVE; + } + return USER_SENTIMENT_NEUTRAL; + } + + /** + * Produces a boolean that can be used to represent "hidden," based on the provided index. + */ + public static boolean getHidden(int index) { + return index % 2 == 0; + } + + /** + * Produces a long to represent lastAudiblyAlerted based on the provided index. + */ + public static long lastAudiblyAlerted(int index) { + return index * 2000L; + } + + /** + * Produces a boolean that can be used to represent "noisy," based on the provided index. + */ + public static boolean getNoisy(int index) { + return index < 1; + } + + /** + * Produces strings that can be used to represent people, based on the provided key and index. + */ + public static ArrayList<String> getPeople(String key, int index) { + ArrayList<String> people = new ArrayList<>(); + for (int i = 0; i < index; i++) { + people.add(i + key); + } + return people; + } + + /** + * Produces a number of snoozeCriteria, based on the provided key and index. + */ + public static ArrayList<SnoozeCriterion> getSnoozeCriteria(String key, int index) { + ArrayList<SnoozeCriterion> snooze = new ArrayList<>(); + for (int i = 0; i < index; i++) { + snooze.add(new SnoozeCriterion(key + i, getExplanation(key), key)); + } + return snooze; + } + + /** + * Produces a list of Actions which can be used to represent smartActions. + * These actions are built from pending intents with intent titles based on the provided + * key, and ids based on the provided index. + */ + public static ArrayList<Notification.Action> getSmartActions(String key, + int index, + TestableContext context) { + ArrayList<Notification.Action> actions = new ArrayList<>(); + for (int i = 0; i < index; i++) { + PendingIntent intent = PendingIntent.getBroadcast( + context, + index /*requestCode*/, + new Intent("ACTION_" + key), + PendingIntent.FLAG_IMMUTABLE /*flags*/); + actions.add(new Notification.Action.Builder(null /*icon*/, key, intent).build()); + } + return actions; + } + + /** + * Produces index number of "smart replies," all based on the provided key and index + */ + public static ArrayList<CharSequence> getSmartReplies(String key, int index) { + ArrayList<CharSequence> choices = new ArrayList<>(); + for (int i = 0; i < index; i++) { + choices.add("choice_" + key + "_" + i); + } + return choices; + } + + /** + * Produces a boolean that can be used to represent canBubble, based on the provided index + */ + public static boolean canBubble(int index) { + return index % 4 == 0; + } + + /** + * Produces a boolean that can be used to represent isTextChanged, based on the provided index. + */ + public static boolean isTextChanged(int index) { + return index % 4 == 0; + } + + /** + * Produces a boolean that can be used to represent isConversation, based on the provided index. + */ + public static boolean isConversation(int index) { + return index % 4 == 0; + } + + /** + * Produces a ShortcutInfo value based on the provided index. + */ + public static ShortcutInfo getShortcutInfo(int index) { + ShortcutInfo si = new ShortcutInfo( + index, String.valueOf(index), "packageName", new ComponentName("1", "1"), null, + "title", 0, "titleResName", "text", 0, "textResName", + "disabledMessage", 0, "disabledMessageResName", + null, null, 0, null, 0, 0, + 0, "iconResName", "bitmapPath", null, 0, + null, null, null, null); + return si; + } + + /** + * Produces a rankingAdjustment value, based on the provided index. + */ + public static int getRankingAdjustment(int index) { + return index % 3 - 1; + } + + /** + * Produces a proposedImportance, based on the provided index. + */ + public static int getProposedImportance(int index) { + return index % 5 - 1; + } + + /** + * Produces a boolean that can be used to represent hasSensitiveContent, based on the provided + * index. + */ + public static boolean hasSensitiveContent(int index) { + return index % 3 == 0; + } + + /** + * Produces a boolean that can be used to represent isBubble, based on the provided index. + */ + public static boolean isBubble(int index) { + return index % 4 == 0; + } + + /** + * Checks that each of the pairs of actions in the two provided lists has identical titles, + * and that the lists have the same number of elements. + */ + public void assertActionsEqual( + List<Notification.Action> expecteds, List<Notification.Action> actuals) { + Assert.assertEquals(expecteds.size(), actuals.size()); + for (int i = 0; i < expecteds.size(); i++) { + Notification.Action expected = expecteds.get(i); + Notification.Action actual = actuals.get(i); + Assert.assertEquals(expected.title.toString(), actual.title.toString()); + } + } + + /** + * Checks that all subelements of the provided NotificationRankingUpdates are equal. + */ + public void detailedAssertEquals(NotificationRankingUpdate a, NotificationRankingUpdate b) { + detailedAssertEquals(a.getRankingMap(), b.getRankingMap()); + } + + /** + * Checks that all subelements of the provided Ranking objects are equal. + */ + public void detailedAssertEquals(String comment, NotificationListenerService.Ranking a, + NotificationListenerService.Ranking b) { + Assert.assertEquals(comment, a.getKey(), b.getKey()); + Assert.assertEquals(comment, a.getRank(), b.getRank()); + Assert.assertEquals(comment, a.matchesInterruptionFilter(), b.matchesInterruptionFilter()); + Assert.assertEquals(comment, a.getLockscreenVisibilityOverride(), + b.getLockscreenVisibilityOverride()); + Assert.assertEquals(comment, a.getSuppressedVisualEffects(), + b.getSuppressedVisualEffects()); + Assert.assertEquals(comment, a.getImportance(), b.getImportance()); + Assert.assertEquals(comment, a.getImportanceExplanation(), b.getImportanceExplanation()); + Assert.assertEquals(comment, a.getOverrideGroupKey(), b.getOverrideGroupKey()); + Assert.assertEquals(comment, a.getChannel().toString(), b.getChannel().toString()); + Assert.assertEquals(comment, a.getAdditionalPeople(), b.getAdditionalPeople()); + Assert.assertEquals(comment, a.getSnoozeCriteria(), b.getSnoozeCriteria()); + Assert.assertEquals(comment, a.canShowBadge(), b.canShowBadge()); + Assert.assertEquals(comment, a.getUserSentiment(), b.getUserSentiment()); + Assert.assertEquals(comment, a.isSuspended(), b.isSuspended()); + Assert.assertEquals(comment, a.getLastAudiblyAlertedMillis(), + b.getLastAudiblyAlertedMillis()); + Assert.assertEquals(comment, a.isNoisy(), b.isNoisy()); + Assert.assertEquals(comment, a.getSmartReplies(), b.getSmartReplies()); + Assert.assertEquals(comment, a.canBubble(), b.canBubble()); + Assert.assertEquals(comment, a.isConversation(), b.isConversation()); + if (a.getConversationShortcutInfo() != null && b.getConversationShortcutInfo() != null) { + Assert.assertEquals(comment, a.getConversationShortcutInfo().getId(), + b.getConversationShortcutInfo().getId()); + } else { + // One or both must be null, so we can check for equality. + Assert.assertEquals(a.getConversationShortcutInfo(), b.getConversationShortcutInfo()); + } + assertActionsEqual(a.getSmartActions(), b.getSmartActions()); + Assert.assertEquals(a.getProposedImportance(), b.getProposedImportance()); + Assert.assertEquals(a.hasSensitiveContent(), b.hasSensitiveContent()); + } + + /** + * Checks that the two RankingMaps have identical keys, and that each Ranking object for + * each of those keys is identical. + */ + public void detailedAssertEquals(NotificationListenerService.RankingMap a, + NotificationListenerService.RankingMap b) { + NotificationListenerService.Ranking arank = new NotificationListenerService.Ranking(); + NotificationListenerService.Ranking brank = new NotificationListenerService.Ranking(); + assertArrayEquals(a.getOrderedKeys(), b.getOrderedKeys()); + for (String key : a.getOrderedKeys()) { + a.getRanking(key, arank); + b.getRanking(key, brank); + detailedAssertEquals("ranking for key <" + key + ">", arank, brank); + } + } + @Before public void setUp() { mNotificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "test channel", @@ -74,8 +435,13 @@ public class NotificationRankingUpdateTest { SystemUiSystemPropertiesFlags.TEST_RESOLVER = null; } - public NotificationListenerService.Ranking createTestRanking(String key, int rank) { + /** + * Creates a mostly empty Test Ranking object with the specified key, rank, and smartActions. + */ + public NotificationListenerService.Ranking createEmptyTestRanking( + String key, int rank, ArrayList<Notification.Action> actions) { NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking(); + ranking.populate( /* key= */ key, /* rank= */ rank, @@ -93,7 +459,7 @@ public class NotificationRankingUpdateTest { /* hidden= */ false, /* lastAudiblyAlertedMs= */ -1, /* noisy= */ false, - /* smartActions= */ null, + /* smartActions= */ actions, /* smartReplies= */ null, /* canBubble= */ false, /* isTextChanged= */ false, @@ -107,54 +473,111 @@ public class NotificationRankingUpdateTest { return ranking; } + // Tests parceling of NotificationRankingUpdate, and by extension, RankingMap and Ranking. @Test - public void testRankingUpdate_rankingConstructor() { - NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123); - NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate( - new NotificationListenerService.Ranking[]{ranking}); + public void testRankingUpdate_parcel() { + NotificationRankingUpdate nru = generateUpdate(getContext()); + Parcel parcel = Parcel.obtain(); + nru.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + NotificationRankingUpdate nru1 = NotificationRankingUpdate.CREATOR.createFromParcel(parcel); + // The rankingUpdate file descriptor is only non-null in the new path. + if (SystemUiSystemPropertiesFlags.getResolver().isEnabled( + SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM)) { + assertTrue(nru1.isFdNotNullAndClosed()); + } + detailedAssertEquals(nru, nru1); + parcel.recycle(); + } + + // Tests parceling of RankingMap and RankingMap.equals + @Test + public void testRankingMap_parcel() { + NotificationListenerService.RankingMap rmap = generateUpdate(getContext()).getRankingMap(); + Parcel parcel = Parcel.obtain(); + rmap.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + NotificationListenerService.RankingMap rmap1 = + NotificationListenerService.RankingMap.CREATOR.createFromParcel(parcel); - NotificationListenerService.RankingMap retrievedRankings = rankingUpdate.getRankingMap(); - NotificationListenerService.Ranking retrievedRanking = - new NotificationListenerService.Ranking(); - assertTrue(retrievedRankings.getRanking(TEST_KEY, retrievedRanking)); - assertEquals(123, retrievedRanking.getRank()); + detailedAssertEquals(rmap, rmap1); + Assert.assertEquals(rmap, rmap1); + parcel.recycle(); } + // Tests parceling of Ranking and Ranking.equals @Test - public void testRankingUpdate_parcelConstructor() { - NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123); - NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate( - new NotificationListenerService.Ranking[]{ranking}); + public void testRanking_parcel() { + NotificationListenerService.Ranking ranking = + generateUpdate(getContext()).getRankingMap().getRawRankingObject(mKeys[0]); + Parcel parcel = Parcel.obtain(); + ranking.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + NotificationListenerService.Ranking ranking1 = + new NotificationListenerService.Ranking(parcel); + detailedAssertEquals("rankings differ: ", ranking, ranking1); + Assert.assertEquals(ranking, ranking1); + parcel.recycle(); + } - Parcel parceledRankingUpdate = Parcel.obtain(); - rankingUpdate.writeToParcel(parceledRankingUpdate, 0); - parceledRankingUpdate.setDataPosition(0); + // Tests NotificationRankingUpdate.equals(), and by extension, RankingMap and Ranking. + @Test + public void testRankingUpdate_equals_legacy() { + NotificationRankingUpdate nru = generateUpdate(getContext()); + NotificationRankingUpdate nru2 = generateUpdate(getContext()); + detailedAssertEquals(nru, nru2); + Assert.assertEquals(nru, nru2); + NotificationListenerService.Ranking tweak = + nru2.getRankingMap().getRawRankingObject(mKeys[0]); + tweak.populate( + tweak.getKey(), + tweak.getRank(), + !tweak.matchesInterruptionFilter(), // note the inversion here! + tweak.getLockscreenVisibilityOverride(), + tweak.getSuppressedVisualEffects(), + tweak.getImportance(), + tweak.getImportanceExplanation(), + tweak.getOverrideGroupKey(), + tweak.getChannel(), + (ArrayList) tweak.getAdditionalPeople(), + (ArrayList) tweak.getSnoozeCriteria(), + tweak.canShowBadge(), + tweak.getUserSentiment(), + tweak.isSuspended(), + tweak.getLastAudiblyAlertedMillis(), + tweak.isNoisy(), + (ArrayList) tweak.getSmartActions(), + (ArrayList) tweak.getSmartReplies(), + tweak.canBubble(), + tweak.isTextChanged(), + tweak.isConversation(), + tweak.getConversationShortcutInfo(), + tweak.getRankingAdjustment(), + tweak.isBubble(), + tweak.getProposedImportance(), + tweak.hasSensitiveContent() + ); + assertNotEquals(nru, nru2); + } - NotificationRankingUpdate retrievedRankingUpdate = new NotificationRankingUpdate( - parceledRankingUpdate); + @Test + public void testRankingUpdate_rankingConstructor() { + NotificationRankingUpdate nru = generateUpdate(getContext()); + NotificationRankingUpdate constructedNru = new NotificationRankingUpdate( + new NotificationListenerService.Ranking[]{ + nru.getRankingMap().getRawRankingObject(mKeys[0]), + nru.getRankingMap().getRawRankingObject(mKeys[1]), + nru.getRankingMap().getRawRankingObject(mKeys[2]), + nru.getRankingMap().getRawRankingObject(mKeys[3]), + nru.getRankingMap().getRawRankingObject(mKeys[4]) + }); - NotificationListenerService.RankingMap retrievedRankings = - retrievedRankingUpdate.getRankingMap(); - assertNotNull(retrievedRankings); - // The rankingUpdate file descriptor is only non-null in the new path. - if (SystemUiSystemPropertiesFlags.getResolver().isEnabled( - SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM)) { - assertTrue(retrievedRankingUpdate.isFdNotNullAndClosed()); - } - NotificationListenerService.Ranking retrievedRanking = - new NotificationListenerService.Ranking(); - assertTrue(retrievedRankings.getRanking(TEST_KEY, retrievedRanking)); - assertEquals(123, retrievedRanking.getRank()); - assertTrue(retrievedRankingUpdate.equals(rankingUpdate)); - parceledRankingUpdate.recycle(); + detailedAssertEquals(nru, constructedNru); } @Test public void testRankingUpdate_emptyParcelInCheck() { - NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123); - NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate( - new NotificationListenerService.Ranking[]{ranking}); - + NotificationRankingUpdate rankingUpdate = generateUpdate(getContext()); Parcel parceledRankingUpdate = Parcel.obtain(); rankingUpdate.writeToParcel(parceledRankingUpdate, 0); @@ -163,37 +586,119 @@ public class NotificationRankingUpdateTest { NotificationRankingUpdate retrievedRankingUpdate = new NotificationRankingUpdate( parceledRankingUpdate); assertNull(retrievedRankingUpdate.getRankingMap()); + parceledRankingUpdate.recycle(); } @Test public void testRankingUpdate_describeContents() { - NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123); - NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate( - new NotificationListenerService.Ranking[]{ranking}); + NotificationRankingUpdate rankingUpdate = generateUpdate(getContext()); assertEquals(0, rankingUpdate.describeContents()); } @Test public void testRankingUpdate_equals() { - NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123); + NotificationListenerService.Ranking ranking = createEmptyTestRanking(TEST_KEY, 123, null); NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate( new NotificationListenerService.Ranking[]{ranking}); - // Reflexive equality. - assertTrue(rankingUpdate.equals(rankingUpdate)); - // Null or wrong class inequality. + // Reflexive equality, including handling nulls properly + detailedAssertEquals(rankingUpdate, rankingUpdate); + // Null or wrong class inequality assertFalse(rankingUpdate.equals(null)); assertFalse(rankingUpdate.equals(ranking)); - // Different ranking contents inequality. - NotificationListenerService.Ranking ranking2 = createTestRanking(TEST_KEY, 456); + // Different rank inequality + NotificationListenerService.Ranking ranking2 = createEmptyTestRanking(TEST_KEY, 456, null); NotificationRankingUpdate rankingUpdate2 = new NotificationRankingUpdate( new NotificationListenerService.Ranking[]{ranking2}); assertFalse(rankingUpdate.equals(rankingUpdate2)); - // Same ranking contents equality. - ranking2 = createTestRanking(TEST_KEY, 123); + // Different key inequality + ranking2 = createEmptyTestRanking(TEST_KEY + "DIFFERENT", 123, null); rankingUpdate2 = new NotificationRankingUpdate( new NotificationListenerService.Ranking[]{ranking2}); - assertTrue(rankingUpdate.equals(rankingUpdate2)); + assertFalse(rankingUpdate.equals(rankingUpdate2)); + } + + @Test + public void testRankingUpdate_writesSmartActionToParcel() { + if (!mRankingUpdateAshmem) { + return; + } + ArrayList<Notification.Action> actions = new ArrayList<>(); + PendingIntent intent = PendingIntent.getBroadcast( + getContext(), + 0 /*requestCode*/, + new Intent("ACTION_" + TEST_KEY), + PendingIntent.FLAG_IMMUTABLE /*flags*/); + actions.add(new Notification.Action.Builder(null /*icon*/, TEST_KEY, intent).build()); + + NotificationListenerService.Ranking ranking = + createEmptyTestRanking(TEST_KEY, 123, actions); + NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate( + new NotificationListenerService.Ranking[]{ranking}); + + Parcel parcel = Parcel.obtain(); + rankingUpdate.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + SharedMemory fd = parcel.readParcelable(getClass().getClassLoader(), SharedMemory.class); + Bundle smartActionsBundle = parcel.readBundle(getClass().getClassLoader()); + + // Assert the file descriptor is valid + assertNotNull(fd); + assertFalse(fd.getFd() == -1); + + // Assert that the smart action is in the parcel + assertNotNull(smartActionsBundle); + ArrayList<Notification.Action> recoveredActions = + smartActionsBundle.getParcelableArrayList(TEST_KEY, Notification.Action.class); + assertNotNull(recoveredActions); + assertEquals(actions.size(), recoveredActions.size()); + assertEquals(actions.get(0).title.toString(), recoveredActions.get(0).title.toString()); + parcel.recycle(); + } + + @Test + public void testRankingUpdate_handlesEmptySmartActionList() { + if (!mRankingUpdateAshmem) { + return; + } + ArrayList<Notification.Action> actions = new ArrayList<>(); + NotificationListenerService.Ranking ranking = + createEmptyTestRanking(TEST_KEY, 123, actions); + NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate( + new NotificationListenerService.Ranking[]{ranking}); + + Parcel parcel = Parcel.obtain(); + rankingUpdate.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + // Ensure that despite an empty actions list, we can still unparcel the update. + NotificationRankingUpdate newRankingUpdate = new NotificationRankingUpdate(parcel); + assertNotNull(newRankingUpdate); + assertNotNull(newRankingUpdate.getRankingMap()); + detailedAssertEquals(rankingUpdate, newRankingUpdate); + parcel.recycle(); + } + + @Test + public void testRankingUpdate_handlesNullSmartActionList() { + if (!mRankingUpdateAshmem) { + return; + } + NotificationListenerService.Ranking ranking = + createEmptyTestRanking(TEST_KEY, 123, null); + NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate( + new NotificationListenerService.Ranking[]{ranking}); + + Parcel parcel = Parcel.obtain(); + rankingUpdate.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + // Ensure that despite an empty actions list, we can still unparcel the update. + NotificationRankingUpdate newRankingUpdate = new NotificationRankingUpdate(parcel); + assertNotNull(newRankingUpdate); + assertNotNull(newRankingUpdate.getRankingMap()); + detailedAssertEquals(rankingUpdate, newRankingUpdate); + parcel.recycle(); } } diff --git a/core/tests/coretests/src/android/widget/DifferentialMotionFlingHelperTest.java b/core/tests/coretests/src/android/widget/DifferentialMotionFlingHelperTest.java index 51c8bc06e878..cce2faf71897 100644 --- a/core/tests/coretests/src/android/widget/DifferentialMotionFlingHelperTest.java +++ b/core/tests/coretests/src/android/widget/DifferentialMotionFlingHelperTest.java @@ -20,6 +20,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import android.view.MotionEvent; +import android.widget.flags.FakeFeatureFlagsImpl; +import android.widget.flags.Flags; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -54,6 +56,8 @@ public class DifferentialMotionFlingHelperTest { private final TestDifferentialMotionFlingTarget mFlingTarget = new TestDifferentialMotionFlingTarget(); + private final FakeFeatureFlagsImpl mFakeWidgetFeatureFlags = new FakeFeatureFlagsImpl(); + private DifferentialMotionFlingHelper mFlingHelper; @Before @@ -62,7 +66,10 @@ public class DifferentialMotionFlingHelperTest { ApplicationProvider.getApplicationContext(), mFlingTarget, mVelocityThresholdCalculator, - mVelocityProvider); + mVelocityProvider, + mFakeWidgetFeatureFlags); + mFakeWidgetFeatureFlags.setFlag( + Flags.FLAG_ENABLE_PLATFORM_WIDGET_DIFFERENTIAL_MOTION_FLING, true); } @Test @@ -139,6 +146,18 @@ public class DifferentialMotionFlingHelperTest { } @Test + public void flingFeatureFlagDisabled_noFlingCalculation() { + mFakeWidgetFeatureFlags.setFlag( + Flags.FLAG_ENABLE_PLATFORM_WIDGET_DIFFERENTIAL_MOTION_FLING, false); + mMinVelocity = 50; + mMaxVelocity = 100; + deliverEventWithVelocity(createPointerEvent(), MotionEvent.AXIS_VSCROLL, 60); + + assertFalse(mVelocityCalculated); + assertEquals(0, mFlingTarget.mLastFlingVelocity, /* delta= */ 0); + } + + @Test public void negativeFlingVelocityAboveMaximum_velocityClamped() { mMinVelocity = 50; mMaxVelocity = 100; diff --git a/core/tests/coretests/src/android/window/SystemPerformanceHinterTests.java b/core/tests/coretests/src/android/window/SystemPerformanceHinterTests.java index 25f5819fb671..263e563bc224 100644 --- a/core/tests/coretests/src/android/window/SystemPerformanceHinterTests.java +++ b/core/tests/coretests/src/android/window/SystemPerformanceHinterTests.java @@ -18,6 +18,8 @@ package android.window; import static android.os.PerformanceHintManager.Session.CPU_LOAD_RESET; import static android.os.PerformanceHintManager.Session.CPU_LOAD_UP; +import static android.view.Surface.FRAME_RATE_CATEGORY_DEFAULT; +import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH; import static android.view.SurfaceControl.FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN; import static android.view.SurfaceControl.FRAME_RATE_SELECTION_STRATEGY_SELF; import static android.window.SystemPerformanceHinter.HINT_ADPF; @@ -150,7 +152,10 @@ public class SystemPerformanceHinterTests { verify(mTransaction).setFrameRateSelectionStrategy( eq(mDefaultDisplayRoot), eq(FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN)); - verify(mTransaction).apply(); + verify(mTransaction).setFrameRateCategory( + eq(mDefaultDisplayRoot), + eq(FRAME_RATE_CATEGORY_HIGH)); + verify(mTransaction).applyAsyncUnsafe(); } @Test @@ -164,7 +169,10 @@ public class SystemPerformanceHinterTests { verify(mTransaction).setFrameRateSelectionStrategy( eq(mDefaultDisplayRoot), eq(FRAME_RATE_SELECTION_STRATEGY_SELF)); - verify(mTransaction).apply(); + verify(mTransaction).setFrameRateCategory( + eq(mDefaultDisplayRoot), + eq(FRAME_RATE_CATEGORY_DEFAULT)); + verify(mTransaction).applyAsyncUnsafe(); } @Test @@ -177,7 +185,7 @@ public class SystemPerformanceHinterTests { // Verify we call SF verify(mTransaction).setEarlyWakeupStart(); - verify(mTransaction).apply(); + verify(mTransaction).applyAsyncUnsafe(); } @Test @@ -189,7 +197,7 @@ public class SystemPerformanceHinterTests { // Verify we call SF verify(mTransaction).setEarlyWakeupEnd(); - verify(mTransaction).apply(); + verify(mTransaction).applyAsyncUnsafe(); } @Test @@ -231,8 +239,11 @@ public class SystemPerformanceHinterTests { verify(mTransaction).setFrameRateSelectionStrategy( eq(mDefaultDisplayRoot), eq(FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN)); + verify(mTransaction).setFrameRateCategory( + eq(mDefaultDisplayRoot), + eq(FRAME_RATE_CATEGORY_HIGH)); verify(mTransaction).setEarlyWakeupStart(); - verify(mTransaction).apply(); + verify(mTransaction).applyAsyncUnsafe(); verify(mAdpfSession).sendHint(eq(CPU_LOAD_UP)); } @@ -248,8 +259,11 @@ public class SystemPerformanceHinterTests { verify(mTransaction).setFrameRateSelectionStrategy( eq(mDefaultDisplayRoot), eq(FRAME_RATE_SELECTION_STRATEGY_SELF)); + verify(mTransaction).setFrameRateCategory( + eq(mDefaultDisplayRoot), + eq(FRAME_RATE_CATEGORY_DEFAULT)); verify(mTransaction).setEarlyWakeupEnd(); - verify(mTransaction).apply(); + verify(mTransaction).applyAsyncUnsafe(); verify(mAdpfSession).sendHint(eq(CPU_LOAD_RESET)); } @@ -265,8 +279,11 @@ public class SystemPerformanceHinterTests { verify(mTransaction).setFrameRateSelectionStrategy( eq(mDefaultDisplayRoot), eq(FRAME_RATE_SELECTION_STRATEGY_SELF)); + verify(mTransaction).setFrameRateCategory( + eq(mDefaultDisplayRoot), + eq(FRAME_RATE_CATEGORY_DEFAULT)); verify(mTransaction).setEarlyWakeupEnd(); - verify(mTransaction).apply(); + verify(mTransaction).applyAsyncUnsafe(); verify(mAdpfSession).sendHint(eq(CPU_LOAD_RESET)); } } @@ -280,8 +297,11 @@ public class SystemPerformanceHinterTests { verify(mTransaction).setFrameRateSelectionStrategy( eq(mDefaultDisplayRoot), eq(FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN)); + verify(mTransaction).setFrameRateCategory( + eq(mDefaultDisplayRoot), + eq(FRAME_RATE_CATEGORY_HIGH)); verify(mTransaction).setEarlyWakeupStart(); - verify(mTransaction).apply(); + verify(mTransaction).applyAsyncUnsafe(); verify(mAdpfSession).sendHint(eq(CPU_LOAD_UP)); reset(mTransaction); reset(mAdpfSession); @@ -290,15 +310,17 @@ public class SystemPerformanceHinterTests { mHinter.startSession(HINT_ALL, DEFAULT_DISPLAY_ID, TEST_OTHER_REASON); // Verify we never call SF and perf manager since session1 is already running verify(mTransaction, never()).setFrameRateSelectionStrategy(any(), anyInt()); + verify(mTransaction, never()).setFrameRateCategory(any(), anyInt()); verify(mTransaction, never()).setEarlyWakeupEnd(); - verify(mTransaction, never()).apply(); + verify(mTransaction, never()).applyAsyncUnsafe(); verify(mAdpfSession, never()).sendHint(anyInt()); session2.close(); // Verify we have not cleaned up because session1 is still running verify(mTransaction, never()).setFrameRateSelectionStrategy(any(), anyInt()); + verify(mTransaction, never()).setFrameRateCategory(any(), anyInt()); verify(mTransaction, never()).setEarlyWakeupEnd(); - verify(mTransaction, never()).apply(); + verify(mTransaction, never()).applyAsyncUnsafe(); verify(mAdpfSession, never()).sendHint(anyInt()); session1.close(); @@ -306,8 +328,11 @@ public class SystemPerformanceHinterTests { verify(mTransaction).setFrameRateSelectionStrategy( eq(mDefaultDisplayRoot), eq(FRAME_RATE_SELECTION_STRATEGY_SELF)); + verify(mTransaction).setFrameRateCategory( + eq(mDefaultDisplayRoot), + eq(FRAME_RATE_CATEGORY_DEFAULT)); verify(mTransaction).setEarlyWakeupEnd(); - verify(mTransaction).apply(); + verify(mTransaction).applyAsyncUnsafe(); verify(mAdpfSession).sendHint(eq(CPU_LOAD_RESET)); } @@ -321,8 +346,11 @@ public class SystemPerformanceHinterTests { verify(mTransaction).setFrameRateSelectionStrategy( eq(mDefaultDisplayRoot), eq(FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN)); + verify(mTransaction).setFrameRateCategory( + eq(mDefaultDisplayRoot), + eq(FRAME_RATE_CATEGORY_HIGH)); verify(mTransaction).setEarlyWakeupStart(); - verify(mTransaction).apply(); + verify(mTransaction).applyAsyncUnsafe(); verify(mAdpfSession).sendHint(eq(CPU_LOAD_UP)); reset(mTransaction); reset(mAdpfSession); @@ -333,8 +361,11 @@ public class SystemPerformanceHinterTests { verify(mTransaction).setFrameRateSelectionStrategy( eq(mSecondaryDisplayRoot), eq(FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN)); + verify(mTransaction).setFrameRateCategory( + eq(mSecondaryDisplayRoot), + eq(FRAME_RATE_CATEGORY_HIGH)); verify(mTransaction, never()).setEarlyWakeupStart(); - verify(mTransaction).apply(); + verify(mTransaction).applyAsyncUnsafe(); verify(mAdpfSession, never()).sendHint(anyInt()); reset(mTransaction); reset(mAdpfSession); @@ -345,11 +376,17 @@ public class SystemPerformanceHinterTests { verify(mTransaction).setFrameRateSelectionStrategy( eq(mDefaultDisplayRoot), eq(FRAME_RATE_SELECTION_STRATEGY_SELF)); + verify(mTransaction).setFrameRateCategory( + eq(mDefaultDisplayRoot), + eq(FRAME_RATE_CATEGORY_DEFAULT)); verify(mTransaction, never()).setFrameRateSelectionStrategy( eq(mSecondaryDisplayRoot), anyInt()); + verify(mTransaction, never()).setFrameRateCategory( + eq(mSecondaryDisplayRoot), + anyInt()); verify(mTransaction, never()).setEarlyWakeupEnd(); - verify(mTransaction).apply(); + verify(mTransaction).applyAsyncUnsafe(); verify(mAdpfSession, never()).sendHint(anyInt()); reset(mTransaction); reset(mAdpfSession); @@ -362,8 +399,11 @@ public class SystemPerformanceHinterTests { verify(mTransaction).setFrameRateSelectionStrategy( eq(mSecondaryDisplayRoot), eq(FRAME_RATE_SELECTION_STRATEGY_SELF)); + verify(mTransaction).setFrameRateCategory( + eq(mSecondaryDisplayRoot), + eq(FRAME_RATE_CATEGORY_DEFAULT)); verify(mTransaction).setEarlyWakeupEnd(); - verify(mTransaction).apply(); + verify(mTransaction).applyAsyncUnsafe(); verify(mAdpfSession).sendHint(eq(CPU_LOAD_RESET)); } diff --git a/core/tests/hdmitests/Android.bp b/core/tests/hdmitests/Android.bp index 3d04937c9195..5f6eaf96a846 100644 --- a/core/tests/hdmitests/Android.bp +++ b/core/tests/hdmitests/Android.bp @@ -30,7 +30,7 @@ android_test { "frameworks-base-testutils", "guava-android-testlib", "platform-test-annotations", - "truth-prebuilt", + "truth", ], libs: ["android.test.runner"], platform_apis: true, diff --git a/core/tests/mockingcoretests/Android.bp b/core/tests/mockingcoretests/Android.bp index fde7c08715c7..2d778b1218d2 100644 --- a/core/tests/mockingcoretests/Android.bp +++ b/core/tests/mockingcoretests/Android.bp @@ -38,7 +38,7 @@ android_test { "androidx.test.ext.junit", "mockito-target-extended-minus-junit4", "platform-test-annotations", - "truth-prebuilt", + "truth", "testables", ], diff --git a/core/tests/nfctests/Android.bp b/core/tests/nfctests/Android.bp index c74600bbab22..f81be494ad18 100644 --- a/core/tests/nfctests/Android.bp +++ b/core/tests/nfctests/Android.bp @@ -27,7 +27,7 @@ android_test { "androidx.test.ext.junit", "androidx.test.rules", "mockito-target-minus-junit4", - "truth-prebuilt", + "truth", ], libs: [ "android.test.runner", diff --git a/core/tests/overlaytests/device_self_targeting/Android.bp b/core/tests/overlaytests/device_self_targeting/Android.bp index 063c5694ab5b..931eac515e31 100644 --- a/core/tests/overlaytests/device_self_targeting/Android.bp +++ b/core/tests/overlaytests/device_self_targeting/Android.bp @@ -30,7 +30,7 @@ android_test { "androidx.test.runner", "androidx.test.ext.junit", "mockito-target-minus-junit4", - "truth-prebuilt", + "truth", ], optimize: { diff --git a/core/tests/packagemonitortests/Android.bp b/core/tests/packagemonitortests/Android.bp index 7b5d7dff0a85..b08850e90d28 100644 --- a/core/tests/packagemonitortests/Android.bp +++ b/core/tests/packagemonitortests/Android.bp @@ -32,7 +32,7 @@ android_test { "compatibility-device-util-axt", "frameworks-base-testutils", "mockito-target-minus-junit4", - "truth-prebuilt", + "truth", ], libs: ["android.test.runner"], platform_apis: true, diff --git a/core/tests/privacytests/Android.bp b/core/tests/privacytests/Android.bp index bc3dd810be8c..4e24cd5d91cb 100644 --- a/core/tests/privacytests/Android.bp +++ b/core/tests/privacytests/Android.bp @@ -14,7 +14,7 @@ android_test { "junit", "rappor-tests", "androidx.test.rules", - "truth-prebuilt", + "truth", ], libs: ["android.test.runner"], platform_apis: true, diff --git a/core/tests/utiltests/Android.bp b/core/tests/utiltests/Android.bp index 3798da592cd5..580e73c331a1 100644 --- a/core/tests/utiltests/Android.bp +++ b/core/tests/utiltests/Android.bp @@ -33,7 +33,7 @@ android_test { "frameworks-base-testutils", "mockito-target-minus-junit4", "androidx.test.ext.junit", - "truth-prebuilt", + "truth", "servicestests-utils", ], diff --git a/core/tests/vibrator/Android.bp b/core/tests/vibrator/Android.bp index 829409a36986..09608e9bf507 100644 --- a/core/tests/vibrator/Android.bp +++ b/core/tests/vibrator/Android.bp @@ -18,7 +18,7 @@ android_test { "androidx.test.runner", "androidx.test.rules", "mockito-target-minus-junit4", - "truth-prebuilt", + "truth", "testng", ], diff --git a/errorprone/Android.bp b/errorprone/Android.bp index ad08026622d1..c1d2235e3324 100644 --- a/errorprone/Android.bp +++ b/errorprone/Android.bp @@ -41,7 +41,7 @@ java_test_host { java_resource_dirs: ["tests/res"], java_resources: [":error_prone_android_framework_testdata"], static_libs: [ - "truth-prebuilt", + "truth", "kxml2-2.3.0", "compile-testing-prebuilt", "error_prone_android_framework_lib", diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index e7814cbd67e7..d1aceafc4e2c 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -114,6 +114,7 @@ public class Canvas extends BaseCanvas { throw new IllegalStateException("Immutable bitmap passed to Canvas constructor"); } throwIfCannotDraw(bitmap); + bitmap.setGainmap(null); mNativeCanvasWrapper = nInitRaster(bitmap.getNativeInstance()); mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation( this, mNativeCanvasWrapper); @@ -178,7 +179,7 @@ public class Canvas extends BaseCanvas { throw new IllegalStateException(); } throwIfCannotDraw(bitmap); - + bitmap.setGainmap(null); nSetBitmap(mNativeCanvasWrapper, bitmap.getNativeInstance()); mDensity = bitmap.mDensity; } diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java index 735bc180c015..52b0b95d3e76 100644 --- a/graphics/java/android/graphics/FontListParser.java +++ b/graphics/java/android/graphics/FontListParser.java @@ -236,7 +236,9 @@ public class FontListParser { } } - return new FontConfig(families, filtered, resultNamedFamilies, lastModifiedDate, + return new FontConfig(families, filtered, resultNamedFamilies, + customization.getLocaleFamilyCustomizations(), + lastModifiedDate, configVersion); } diff --git a/graphics/java/android/graphics/fonts/FontCustomizationParser.java b/graphics/java/android/graphics/fonts/FontCustomizationParser.java index b458dd9021d0..6e04a2f5e405 100644 --- a/graphics/java/android/graphics/fonts/FontCustomizationParser.java +++ b/graphics/java/android/graphics/fonts/FontCustomizationParser.java @@ -22,6 +22,7 @@ import static android.text.FontConfig.NamedFamilyList; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.FontListParser; +import android.text.FontConfig; import android.util.Xml; import org.xmlpull.v1.XmlPullParser; @@ -34,6 +35,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; /** @@ -52,14 +54,19 @@ public class FontCustomizationParser { private final List<Alias> mAdditionalAliases; + private final List<FontConfig.Customization.LocaleFallback> mLocaleFamilyCustomizations; + public Result() { mAdditionalNamedFamilies = Collections.emptyMap(); + mLocaleFamilyCustomizations = Collections.emptyList(); mAdditionalAliases = Collections.emptyList(); } public Result(Map<String, NamedFamilyList> additionalNamedFamilies, + List<FontConfig.Customization.LocaleFallback> localeFamilyCustomizations, List<Alias> additionalAliases) { mAdditionalNamedFamilies = additionalNamedFamilies; + mLocaleFamilyCustomizations = localeFamilyCustomizations; mAdditionalAliases = additionalAliases; } @@ -70,6 +77,10 @@ public class FontCustomizationParser { public List<Alias> getAdditionalAliases() { return mAdditionalAliases; } + + public List<FontConfig.Customization.LocaleFallback> getLocaleFamilyCustomizations() { + return mLocaleFamilyCustomizations; + } } /** @@ -89,7 +100,9 @@ public class FontCustomizationParser { } private static Result validateAndTransformToResult( - List<NamedFamilyList> families, List<Alias> aliases) { + List<NamedFamilyList> families, + List<FontConfig.Customization.LocaleFallback> outLocaleFamilies, + List<Alias> aliases) { HashMap<String, NamedFamilyList> namedFamily = new HashMap<>(); for (int i = 0; i < families.size(); ++i) { final NamedFamilyList family = families.get(i); @@ -105,7 +118,7 @@ public class FontCustomizationParser { + "requires fallackTarget attribute"); } } - return new Result(namedFamily, aliases); + return new Result(namedFamily, outLocaleFamilies, aliases); } private static Result readFamilies( @@ -115,12 +128,13 @@ public class FontCustomizationParser { ) throws XmlPullParserException, IOException { List<NamedFamilyList> families = new ArrayList<>(); List<Alias> aliases = new ArrayList<>(); + List<FontConfig.Customization.LocaleFallback> outLocaleFamilies = new ArrayList<>(); parser.require(XmlPullParser.START_TAG, null, "fonts-modification"); while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() != XmlPullParser.START_TAG) continue; String tag = parser.getName(); if (tag.equals("family")) { - readFamily(parser, fontDir, families, updatableFontMap); + readFamily(parser, fontDir, families, outLocaleFamilies, updatableFontMap); } else if (tag.equals("family-list")) { readFamilyList(parser, fontDir, families, updatableFontMap); } else if (tag.equals("alias")) { @@ -129,13 +143,14 @@ public class FontCustomizationParser { FontListParser.skip(parser); } } - return validateAndTransformToResult(families, aliases); + return validateAndTransformToResult(families, outLocaleFamilies, aliases); } private static void readFamily( @NonNull XmlPullParser parser, @NonNull String fontDir, @NonNull List<NamedFamilyList> out, + @NonNull List<FontConfig.Customization.LocaleFallback> outCustomization, @Nullable Map<String, File> updatableFontMap) throws XmlPullParserException, IOException { final String customizationType = parser.getAttributeValue(null, "customizationType"); @@ -148,6 +163,29 @@ public class FontCustomizationParser { if (fontFamily != null) { out.add(fontFamily); } + } else if (customizationType.equals("new-locale-family")) { + final String lang = parser.getAttributeValue(null, "lang"); + final String op = parser.getAttributeValue(null, "operation"); + final int intOp; + if (op.equals("append")) { + intOp = FontConfig.Customization.LocaleFallback.OPERATION_APPEND; + } else if (op.equals("prepend")) { + intOp = FontConfig.Customization.LocaleFallback.OPERATION_PREPEND; + } else if (op.equals("replace")) { + intOp = FontConfig.Customization.LocaleFallback.OPERATION_REPLACE; + } else { + throw new IllegalArgumentException("Unknown operation=" + op); + } + + final FontConfig.FontFamily family = FontListParser.readFamily( + parser, fontDir, updatableFontMap, false); + + // For ignoring the customization, consume the new-locale-family element but don't + // register any customizations. + if (com.android.text.flags.Flags.customLocaleFallback()) { + outCustomization.add(new FontConfig.Customization.LocaleFallback( + Locale.forLanguageTag(lang), intOp, family)); + } } else { throw new IllegalArgumentException("Unknown customizationType=" + customizationType); } diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java index d4e35b30c8d0..618aa5b5019c 100644 --- a/graphics/java/android/graphics/fonts/SystemFonts.java +++ b/graphics/java/android/graphics/fonts/SystemFonts.java @@ -16,10 +16,15 @@ package android.graphics.fonts; +import static android.text.FontConfig.Customization.LocaleFallback.OPERATION_APPEND; +import static android.text.FontConfig.Customization.LocaleFallback.OPERATION_PREPEND; +import static android.text.FontConfig.Customization.LocaleFallback.OPERATION_REPLACE; + import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.FontListParser; import android.graphics.Typeface; +import android.os.LocaleList; import android.text.FontConfig; import android.util.ArrayMap; import android.util.Log; @@ -38,6 +43,7 @@ import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -119,7 +125,6 @@ public final class SystemFonts { } } - final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily( defaultFonts, languageTags, variant, xmlFamily.getVariableFontFamilyType(), false, cache); @@ -300,11 +305,11 @@ public final class SystemFonts { } catch (IOException e) { Log.e(TAG, "Failed to open/read system font configurations.", e); return new FontConfig(Collections.emptyList(), Collections.emptyList(), - Collections.emptyList(), 0, 0); + Collections.emptyList(), Collections.emptyList(), 0, 0); } catch (XmlPullParserException e) { Log.e(TAG, "Failed to parse the system font configuration.", e); return new FontConfig(Collections.emptyList(), Collections.emptyList(), - Collections.emptyList(), 0, 0); + Collections.emptyList(), Collections.emptyList(), 0, 0); } } @@ -328,6 +333,8 @@ public final class SystemFonts { ArrayMap<String, ByteBuffer> outBufferCache) { final ArrayMap<String, NativeFamilyListSet> fallbackListMap = new ArrayMap<>(); + final List<FontConfig.Customization.LocaleFallback> localeFallbacks = + fontConfig.getLocaleFallbackCustomizations(); final List<FontConfig.NamedFamilyList> namedFamilies = fontConfig.getNamedFamilyLists(); for (int i = 0; i < namedFamilies.size(); ++i) { @@ -336,10 +343,54 @@ public final class SystemFonts { } // Then, add fallback fonts to the fallback map. + final List<FontConfig.Customization.LocaleFallback> customizations = new ArrayList<>(); final List<FontConfig.FontFamily> xmlFamilies = fontConfig.getFontFamilies(); + final SparseIntArray seenCustomization = new SparseIntArray(); for (int i = 0; i < xmlFamilies.size(); i++) { final FontConfig.FontFamily xmlFamily = xmlFamilies.get(i); - pushFamilyToFallback(xmlFamily, fallbackListMap, outBufferCache); + + customizations.clear(); + for (int j = 0; j < localeFallbacks.size(); ++j) { + if (seenCustomization.get(j, -1) != -1) { + continue; // The customization is already applied. + } + FontConfig.Customization.LocaleFallback localeFallback = localeFallbacks.get(j); + if (scriptMatch(xmlFamily.getLocaleList(), localeFallback.getScript())) { + customizations.add(localeFallback); + seenCustomization.put(j, 1); + } + } + + if (customizations.isEmpty()) { + pushFamilyToFallback(xmlFamily, fallbackListMap, outBufferCache); + } else { + for (int j = 0; j < customizations.size(); ++j) { + FontConfig.Customization.LocaleFallback localeFallback = customizations.get(j); + if (localeFallback.getOperation() == OPERATION_PREPEND) { + pushFamilyToFallback(localeFallback.getFamily(), fallbackListMap, + outBufferCache); + } + } + boolean isReplaced = false; + for (int j = 0; j < customizations.size(); ++j) { + FontConfig.Customization.LocaleFallback localeFallback = customizations.get(j); + if (localeFallback.getOperation() == OPERATION_REPLACE) { + pushFamilyToFallback(localeFallback.getFamily(), fallbackListMap, + outBufferCache); + isReplaced = true; + } + } + if (!isReplaced) { // If nothing is replaced, push the original one. + pushFamilyToFallback(xmlFamily, fallbackListMap, outBufferCache); + } + for (int j = 0; j < customizations.size(); ++j) { + FontConfig.Customization.LocaleFallback localeFallback = customizations.get(j); + if (localeFallback.getOperation() == OPERATION_APPEND) { + pushFamilyToFallback(localeFallback.getFamily(), fallbackListMap, + outBufferCache); + } + } + } } // Build the font map and fallback map. @@ -365,4 +416,42 @@ public final class SystemFonts { Typeface.initSystemDefaultTypefaces(fallbackMap, fontConfig.getAliases(), result); return result; } + + private static boolean scriptMatch(LocaleList localeList, String targetScript) { + if (localeList == null || localeList.isEmpty()) { + return false; + } + for (int i = 0; i < localeList.size(); ++i) { + Locale locale = localeList.get(i); + if (locale == null) { + continue; + } + String baseScript = FontConfig.resolveScript(locale); + if (baseScript.equals(targetScript)) { + return true; + } + + // Subtag match + if (targetScript.equals("Bopo") && baseScript.equals("Hanb")) { + // Hanb is Han with Bopomofo. + return true; + } else if (targetScript.equals("Hani")) { + if (baseScript.equals("Hanb") || baseScript.equals("Hans") + || baseScript.equals("Hant") || baseScript.equals("Kore") + || baseScript.equals("Jpan")) { + // Han id suppoted by Taiwanese, Traditional Chinese, Simplified Chinese, Korean + // and Japanese. + return true; + } + } else if (targetScript.equals("Hira") || targetScript.equals("Hrkt") + || targetScript.equals("Kana")) { + if (baseScript.equals("Jpan") || baseScript.equals("Hrkt")) { + // Hiragana, Hiragana-Katakana, Katakana is supported by Japanese and + // Hiragana-Katakana script. + return true; + } + } + } + return false; + } } diff --git a/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java index e81525fb7d60..f5e5803d4796 100644 --- a/graphics/java/android/graphics/text/LineBreakConfig.java +++ b/graphics/java/android/graphics/text/LineBreakConfig.java @@ -134,10 +134,25 @@ public final class LineBreakConfig { */ public static final int LINE_BREAK_STYLE_STRICT = 3; + /** + * The line break style that used for preventing automatic line breaking. + * + * This is useful when you want to preserve some words in the same line by using + * {@link android.text.style.LineBreakConfigSpan} or + * {@link android.text.style.LineBreakConfigSpan.NoBreakSpan} as a shorthand. + * Note that even if this style is specified, the grapheme based line break is still performed + * for preventing clipping text. + * + * @see android.text.style.LineBreakConfigSpan + * @see android.text.style.LineBreakConfigSpan.NoBreakSpan + */ + @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) + public static final int LINE_BREAK_STYLE_NO_BREAK = 4; + /** @hide */ @IntDef(prefix = { "LINE_BREAK_STYLE_" }, value = { LINE_BREAK_STYLE_NONE, LINE_BREAK_STYLE_LOOSE, LINE_BREAK_STYLE_NORMAL, - LINE_BREAK_STYLE_STRICT, LINE_BREAK_STYLE_UNSPECIFIED + LINE_BREAK_STYLE_STRICT, LINE_BREAK_STYLE_UNSPECIFIED, LINE_BREAK_STYLE_NO_BREAK }) @Retention(RetentionPolicy.SOURCE) public @interface LineBreakStyle {} diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java index 0f3488bbe8d1..31c2eb2efaed 100644 --- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java +++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java @@ -28,8 +28,8 @@ import android.system.keystore2.ResponseCode; import android.util.Log; /** - * @hide This is the client side for IKeystoreUserManager AIDL. - * It shall only be used by the LockSettingsService. + * @hide This is the client side for IKeystoreMaintenance AIDL. + * It is used mainly by LockSettingsService. */ public class AndroidKeyStoreMaintenance { private static final String TAG = "AndroidKeyStoreMaintenance"; @@ -66,7 +66,7 @@ public class AndroidKeyStoreMaintenance { } /** - * Informs Keystore 2.0 about removing a usergit mer + * Informs Keystore 2.0 about removing a user * * @param userId - Android user id of the user being removed * @return 0 if successful or a {@code ResponseCode} @@ -91,7 +91,7 @@ public class AndroidKeyStoreMaintenance { * * @param userId - Android user id of the user * @param password - a secret derived from the synthetic password provided by the - * LockSettingService + * LockSettingsService * @return 0 if successful or a {@code ResponseCode} * @hide */ @@ -110,7 +110,7 @@ public class AndroidKeyStoreMaintenance { } /** - * Informs Keystore 2.0 that an app was uninstalled and the corresponding namspace is to + * Informs Keystore 2.0 that an app was uninstalled and the corresponding namespace is to * be cleared. */ public static int clearNamespace(@Domain int domain, long namespace) { @@ -172,10 +172,10 @@ public class AndroidKeyStoreMaintenance { * namespace. * * @return * 0 on success - * * KEY_NOT_FOUND if the source did not exists. + * * KEY_NOT_FOUND if the source did not exist. * * PERMISSION_DENIED if any of the required permissions was missing. * * INVALID_ARGUMENT if the destination was occupied or any domain value other than - * the allowed once were specified. + * the allowed ones was specified. * * SYSTEM_ERROR if an unexpected error occurred. */ public static int migrateKeyNamespace(KeyDescriptor source, KeyDescriptor destination) { diff --git a/libs/WindowManager/Jetpack/tests/unittest/Android.bp b/libs/WindowManager/Jetpack/tests/unittest/Android.bp index b6e743a2b7e1..ed2ff2de245b 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/Android.bp +++ b/libs/WindowManager/Jetpack/tests/unittest/Android.bp @@ -37,7 +37,7 @@ android_test { "androidx.test.rules", "androidx.test.ext.junit", "mockito-target-extended-minus-junit4", - "truth-prebuilt", + "truth", "testables", "platform-test-annotations", ], diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 7a309f5758a0..1f6f7aeadd45 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -143,7 +143,9 @@ <dimen name="bubble_expanded_view_padding">16dp</dimen> <!-- Padding for the edge of the expanded view that is closest to the edge of the screen used when displaying in landscape on a large screen. --> - <dimen name="bubble_expanded_view_largescreen_landscape_padding">128dp</dimen> + <dimen name="bubble_expanded_view_largescreen_landscape_padding">102dp</dimen> + <!-- The width of the expanded view on large screens. --> + <dimen name="bubble_expanded_view_largescreen_width">540dp</dimen> <!-- This should be at least the size of bubble_expanded_view_padding; it is used to include a slight touch slop around the expanded view. --> <dimen name="bubble_expanded_view_slop">8dp</dimen> 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 ea7053d8ee49..17e06e93b3a8 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 @@ -54,10 +54,6 @@ public class BubblePositioner { public static final float FLYOUT_MAX_WIDTH_PERCENT_LARGE_SCREEN = 0.3f; /** The max percent of screen width to use for the flyout on phone. */ public static final float FLYOUT_MAX_WIDTH_PERCENT = 0.6f; - /** The percent of screen width for the expanded view on a large screen. **/ - private static final float EXPANDED_VIEW_LARGE_SCREEN_LANDSCAPE_WIDTH_PERCENT = 0.48f; - /** The percent of screen width for the expanded view on a large screen. **/ - private static final float EXPANDED_VIEW_LARGE_SCREEN_PORTRAIT_WIDTH_PERCENT = 0.70f; /** The percent of screen width for the expanded view on a small tablet. **/ private static final float EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT = 0.72f; /** The percent of screen width for the expanded view when shown in the bubble bar. **/ @@ -95,6 +91,7 @@ public class BubblePositioner { private int mPointerWidth; private int mPointerHeight; private int mPointerOverlap; + private int mManageButtonHeightIncludingMargins; private int mManageButtonHeight; private int mOverflowHeight; private int mMinimumFlyoutWidthLargeScreen; @@ -176,21 +173,20 @@ public class BubblePositioner { mExpandedViewLargeScreenWidth = (int) (bounds.width() * EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT); } else { - mExpandedViewLargeScreenWidth = isLandscape() - ? (int) (bounds.width() * EXPANDED_VIEW_LARGE_SCREEN_LANDSCAPE_WIDTH_PERCENT) - : (int) (bounds.width() * EXPANDED_VIEW_LARGE_SCREEN_PORTRAIT_WIDTH_PERCENT); + mExpandedViewLargeScreenWidth = + res.getDimensionPixelSize(R.dimen.bubble_expanded_view_largescreen_width); } if (mIsLargeScreen) { - if (isLandscape() && !mIsSmallTablet) { + if (mIsSmallTablet) { + final int centeredInset = (bounds.width() - mExpandedViewLargeScreenWidth) / 2; + mExpandedViewLargeScreenInsetClosestEdge = centeredInset; + mExpandedViewLargeScreenInsetFurthestEdge = centeredInset; + } else { mExpandedViewLargeScreenInsetClosestEdge = res.getDimensionPixelSize( R.dimen.bubble_expanded_view_largescreen_landscape_padding); mExpandedViewLargeScreenInsetFurthestEdge = bounds.width() - mExpandedViewLargeScreenInsetClosestEdge - mExpandedViewLargeScreenWidth; - } else { - final int centeredInset = (bounds.width() - mExpandedViewLargeScreenWidth) / 2; - mExpandedViewLargeScreenInsetClosestEdge = centeredInset; - mExpandedViewLargeScreenInsetFurthestEdge = centeredInset; } } else { mExpandedViewLargeScreenInsetClosestEdge = mExpandedViewPadding; @@ -202,7 +198,9 @@ public class BubblePositioner { mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height); mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin); mPointerOverlap = res.getDimensionPixelSize(R.dimen.bubble_pointer_overlap); - mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_total_height); + mManageButtonHeightIncludingMargins = + res.getDimensionPixelSize(R.dimen.bubble_manage_button_total_height); + mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_height); mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height); mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height); mMinimumFlyoutWidthLargeScreen = res.getDimensionPixelSize( @@ -420,7 +418,7 @@ public class BubblePositioner { int pointerSize = showBubblesVertically() ? mPointerWidth : (mPointerHeight + mPointerMargin); - int bottomPadding = isOverflow ? mExpandedViewPadding : mManageButtonHeight; + int bottomPadding = isOverflow ? mExpandedViewPadding : mManageButtonHeightIncludingMargins; return getAvailableRect().height() - expandedContainerY - paddingTop @@ -438,6 +436,15 @@ public class BubblePositioner { // overflow in landscape on phone is max return MAX_HEIGHT; } + + if (mIsLargeScreen && !mIsSmallTablet && !isOverflow) { + // the expanded view height on large tablets is calculated based on the shortest screen + // size and is the same in both portrait and landscape + int maxVerticalInset = Math.max(mInsets.top, mInsets.bottom); + int shortestScreenSide = Math.min(mScreenRect.height(), mScreenRect.width()); + return shortestScreenSide - 2 * maxVerticalInset - mManageButtonHeight; + } + float desiredHeight = isOverflow ? mOverflowHeight : ((Bubble) bubble).getDesiredHeight(mContext); @@ -466,7 +473,8 @@ public class BubblePositioner { return topAlignment; } // If we're here, we're showing vertically & developer has made height less than maximum. - int manageButtonHeight = isOverflow ? mExpandedViewPadding : mManageButtonHeight; + int manageButtonHeight = + isOverflow ? mExpandedViewPadding : mManageButtonHeightIncludingMargins; float pointerPosition = getPointerPosition(bubblePosition); float bottomIfCentered = pointerPosition + (expandedViewHeight / 2) + manageButtonHeight; float topIfCentered = pointerPosition - (expandedViewHeight / 2); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TvWindowMenuActionButton.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TvWindowMenuActionButton.java index 931cf0cee28c..c6c9b3562308 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TvWindowMenuActionButton.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TvWindowMenuActionButton.java @@ -94,6 +94,10 @@ public class TvWindowMenuActionButton extends RelativeLayout { mCurrentIcon = icon; // Remove old image while waiting for the new one to load. mIconImageView.setImageDrawable(null); + if (icon.getType() == Icon.TYPE_URI || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) { + // Disallow loading icon from content URI + return; + } icon.loadDrawableAsync(mContext, d -> { // The image hasn't been set any other way and the drawable belongs to the most // recently set Icon. 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 11aa054676cb..5dfba5e7ff1d 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 @@ -494,13 +494,14 @@ public abstract class WMShellModule { ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler, @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository, LaunchAdjacentController launchAdjacentController, + RecentsTransitionHandler recentsTransitionHandler, @ShellMainThread ShellExecutor mainExecutor ) { return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController, displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, transitions, enterDesktopTransitionHandler, exitDesktopTransitionHandler, toggleResizeDesktopTaskTransitionHandler, desktopModeTaskRepository, - launchAdjacentController, mainExecutor); + launchAdjacentController, recentsTransitionHandler, mainExecutor); } @WMSingleton 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 09ba4f79326e..412a5b5a6997 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 @@ -60,6 +60,8 @@ import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.TO_DESKTOP_INDICATOR import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE +import com.android.wm.shell.recents.RecentsTransitionHandler +import com.android.wm.shell.recents.RecentsTransitionStateListener import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_ENTER_DESKTOP import com.android.wm.shell.sysui.ShellCommandHandler @@ -68,7 +70,6 @@ import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.sysui.ShellSharedConstants import com.android.wm.shell.transition.OneShotRemoteHandler import com.android.wm.shell.transition.Transitions -import com.android.wm.shell.transition.Transitions.TransitionHandler import com.android.wm.shell.util.KtProtoLog import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration import com.android.wm.shell.windowdecor.MoveToDesktopAnimator @@ -93,6 +94,7 @@ class DesktopTasksController( ToggleResizeDesktopTaskTransitionHandler, private val desktopModeTaskRepository: DesktopModeTaskRepository, private val launchAdjacentController: LaunchAdjacentController, + private val recentsTransitionHandler: RecentsTransitionHandler, @ShellMainThread private val mainExecutor: ShellExecutor ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler { @@ -119,6 +121,8 @@ class DesktopTasksController( com.android.wm.shell.R.dimen.desktop_mode_transition_area_width ) + private var recentsAnimationRunning = false + // This is public to avoid cyclic dependency; it is set by SplitScreenController lateinit var splitScreenController: SplitScreenController @@ -139,6 +143,19 @@ class DesktopTasksController( ) transitions.addHandler(this) desktopModeTaskRepository.addVisibleTasksListener(taskVisibilityListener, mainExecutor) + + recentsTransitionHandler.addTransitionStateListener( + object : RecentsTransitionStateListener { + override fun onAnimationStateChanged(running: Boolean) { + KtProtoLog.v( + WM_SHELL_DESKTOP_MODE, + "DesktopTasksController: recents animation state changed running=%b", + running + ) + recentsAnimationRunning = running + } + } + ) } /** Show all tasks, that are part of the desktop, on top of launcher */ @@ -644,6 +661,10 @@ class DesktopTasksController( val triggerTask = request.triggerTask val shouldHandleRequest = when { + recentsAnimationRunning -> { + reason = "recents animation is running" + false + } // Only handle open or to front transitions request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> { reason = "transition type not handled (${request.type})" 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 ead2f9cbd1ad..d31476c63890 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 @@ -54,6 +54,7 @@ import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.IResultReceiver; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.protolog.ShellProtoLogGroup; @@ -279,7 +280,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { mDeathHandler = () -> { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.DeathRecipient: binder died", mInstanceId); - finish(mWillFinishToHome, false /* leaveHint */); + finish(mWillFinishToHome, false /* leaveHint */, null /* finishCb */); }; try { mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */); @@ -313,7 +314,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } if (mFinishCB != null) { - finishInner(toHome, false /* userLeave */); + finishInner(toHome, false /* userLeave */, null /* finishCb */); } else { cleanUp(); } @@ -670,7 +671,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { // now and let it do its animation (since recents is going to be occluded). sendCancelWithSnapshots(); mExecutor.executeDelayed( - () -> finishInner(true /* toHome */, false /* userLeaveHint */), 0); + () -> finishInner(true /* toHome */, false /* userLeaveHint */, + null /* finishCb */), 0); return; } if (recentsOpening != null) { @@ -899,11 +901,12 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { @Override @SuppressLint("NewApi") - public void finish(boolean toHome, boolean sendUserLeaveHint) { - mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint)); + public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) { + mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint, finishCb)); } - private void finishInner(boolean toHome, boolean sendUserLeaveHint) { + private void finishInner(boolean toHome, boolean sendUserLeaveHint, + IResultReceiver runnerFinishCb) { if (mFinishCB == null) { Slog.e(TAG, "Duplicate call to finish"); return; @@ -993,6 +996,16 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } cleanUp(); finishCB.onTransitionFinished(wct.isEmpty() ? null : wct); + 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); + } + } } @Override 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 5e2c61b9d3cd..b2948667f9e6 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 @@ -143,6 +143,8 @@ import com.android.wm.shell.util.SplitBounds; import com.android.wm.shell.util.TransitionUtil; import com.android.wm.shell.windowdecor.WindowDecorViewModel; +import dalvik.annotation.optimization.NeverCompile; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; @@ -3109,6 +3111,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER); } + @NeverCompile @Override 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 83dc7fa5e869..e828eedc275c 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 @@ -23,6 +23,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; + import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; @@ -693,9 +694,19 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { + Transitions.TransitionFinishCallback finishCB = wct -> { + mixed.mInFlightSubAnimations--; + if (mixed.mInFlightSubAnimations == 0) { + mActiveTransitions.remove(mixed); + finishCallback.onTransitionFinished(wct); + } + }; + + mixed.mInFlightSubAnimations++; boolean consumed = mRecentsHandler.startAnimation( - mixed.mTransition, info, startTransaction, finishTransaction, finishCallback); + mixed.mTransition, info, startTransaction, finishTransaction, finishCB); if (!consumed) { + mixed.mInFlightSubAnimations--; return false; } if (mDesktopTasksController != null) { 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 6062e34cd601..335a5886ba28 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 @@ -44,6 +44,7 @@ import android.window.WindowContainerTransaction; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.desktopmode.DesktopModeStatus; import java.util.function.Supplier; @@ -283,10 +284,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> // Task surface itself float shadowRadius = loadDimension(resources, params.mShadowRadiusId); - 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; final Point taskPosition = mTaskInfo.positionInParent; if (isFullscreen) { // Setting the task crop to the width/height stops input events from being sent to @@ -302,13 +299,22 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> finishT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight); } startT.setShadowRadius(mTaskSurface, shadowRadius) - .setColor(mTaskSurface, mTmpColor) .show(mTaskSurface); finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y) .setShadowRadius(mTaskSurface, shadowRadius); 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); + } else if (!DesktopModeStatus.isVeiledResizeEnabled()) { + startT.unsetColor(mTaskSurface); } if (mCaptionWindowManager == null) { diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp index 54f94986d90c..d09a90cd7dc7 100644 --- a/libs/WindowManager/Shell/tests/unittest/Android.bp +++ b/libs/WindowManager/Shell/tests/unittest/Android.bp @@ -45,7 +45,7 @@ android_test { "kotlinx-coroutines-core", "mockito-kotlin2", "mockito-target-extended-minus-junit4", - "truth-prebuilt", + "truth", "testables", "platform-test-annotations", "servicestests-utils", diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java index 58d9a6486ff2..287a97c9b5b0 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java @@ -22,20 +22,24 @@ import static android.view.View.LAYOUT_DIRECTION_LTR; import static android.view.View.LAYOUT_DIRECTION_RTL; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import android.content.Intent; import android.content.res.Configuration; import android.graphics.Insets; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; +import android.os.UserHandle; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableResources; +import android.util.DisplayMetrics; import android.view.WindowInsets; import android.view.WindowManager; import android.view.WindowMetrics; @@ -257,6 +261,27 @@ public class BubblePositionerTest extends ShellTestCase { assertThat(mPositioner.hasUserModifiedDefaultPosition()).isTrue(); } + @Test + public void testExpandedViewHeight_onLargeTablet() { + Insets insets = Insets.of(10, 20, 5, 15); + Rect screenBounds = new Rect(0, 0, 1800, 2600); + + new WindowManagerConfig() + .setLargeScreen() + .setInsets(insets) + .setScreenBounds(screenBounds) + .setUpConfig(); + mPositioner.update(); + + Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName()); + Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor()); + + int manageButtonHeight = + mContext.getResources().getDimensionPixelSize(R.dimen.bubble_manage_button_height); + float expectedHeight = 1800 - 2 * 20 - manageButtonHeight; + assertThat(mPositioner.getExpandedViewHeight(bubble)).isWithin(0.1f).of(expectedHeight); + } + /** * Calculates the Y position bubbles should be placed based on the config. Based on * the calculations in {@link BubblePositioner#getDefaultStartPosition()} and @@ -323,6 +348,8 @@ public class BubblePositionerTest extends ShellTestCase { ? MIN_WIDTH_FOR_TABLET : MIN_WIDTH_FOR_TABLET - 1; mConfiguration.orientation = mOrientation; + mConfiguration.screenWidthDp = pxToDp(mScreenBounds.width()); + mConfiguration.screenHeightDp = pxToDp(mScreenBounds.height()); when(mConfiguration.getLayoutDirection()).thenReturn(mLayoutDirection); WindowInsets windowInsets = mock(WindowInsets.class); @@ -331,5 +358,11 @@ public class BubblePositionerTest extends ShellTestCase { when(mWindowMetrics.getBounds()).thenReturn(mScreenBounds); when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics); } + + private int pxToDp(float px) { + int dpi = mContext.getResources().getDisplayMetrics().densityDpi; + float dp = px / ((float) dpi / DisplayMetrics.DENSITY_DEFAULT); + return (int) dp; + } } } 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 dea161786da2..ebcb6407a6fd 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 @@ -54,6 +54,8 @@ import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreef 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.recents.RecentsTransitionHandler +import com.android.wm.shell.recents.RecentsTransitionStateListener import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController @@ -101,11 +103,13 @@ class DesktopTasksControllerTest : ShellTestCase() { @Mock lateinit var launchAdjacentController: LaunchAdjacentController @Mock lateinit var desktopModeWindowDecoration: DesktopModeWindowDecoration @Mock lateinit var splitScreenController: SplitScreenController + @Mock lateinit var recentsTransitionHandler: RecentsTransitionHandler private lateinit var mockitoSession: StaticMockitoSession private lateinit var controller: DesktopTasksController private lateinit var shellInit: ShellInit private lateinit var desktopModeTaskRepository: DesktopModeTaskRepository + private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener private val shellExecutor = TestShellExecutor() // Mock running tasks are registered here so we can get the list from mock shell task organizer @@ -126,6 +130,10 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.splitScreenController = splitScreenController shellInit.init() + + val captor = ArgumentCaptor.forClass(RecentsTransitionStateListener::class.java) + verify(recentsTransitionHandler).addTransitionStateListener(captor.capture()) + recentsTransitionStateListener = captor.value } private fun createController(): DesktopTasksController { @@ -144,6 +152,7 @@ class DesktopTasksControllerTest : ShellTestCase() { mToggleResizeDesktopTaskTransitionHandler, desktopModeTaskRepository, launchAdjacentController, + recentsTransitionHandler, shellExecutor ) } @@ -355,7 +364,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun moveToDesktop_splitTaskExitsSplit() { - var task = setUpSplitScreenTask() + val task = setUpSplitScreenTask() controller.moveToDesktop(desktopModeWindowDecoration, task) val wct = getLatestMoveToDesktopWct() assertThat(wct.changes[task.token.asBinder()]?.windowingMode) @@ -367,7 +376,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun moveToDesktop_fullscreenTaskDoesNotExitSplit() { - var task = setUpFullscreenTask() + val task = setUpFullscreenTask() controller.moveToDesktop(desktopModeWindowDecoration, task) val wct = getLatestMoveToDesktopWct() assertThat(wct.changes[task.token.asBinder()]?.windowingMode) @@ -666,6 +675,20 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test + fun handleRequest_recentsAnimationRunning_returnNull() { + // Set up a visible freeform task so a fullscreen task should be converted to freeform + val freeformTask = setUpFreeformTask() + markTaskVisible(freeformTask) + + // Mark recents animation running + recentsTransitionStateListener.onAnimationStateChanged(true) + + // Open a fullscreen task, check that it does not result in a WCT with changes to it + val fullscreenTask = createFullscreenTask() + assertThat(controller.handleRequest(Binder(), createTransition(fullscreenTask))).isNull() + } + + @Test fun stashDesktopApps_stateUpdates() { whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index 966a99eea925..fcb7863429d6 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -17,7 +17,9 @@ package com.android.wm.shell.windowdecor; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlBuilder; import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction; @@ -36,6 +38,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.same; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.quality.Strictness.LENIENT; import android.app.ActivityManager; import android.content.Context; @@ -59,10 +62,12 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; +import com.android.dx.mockito.inline.extended.StaticMockitoSession; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.desktopmode.DesktopModeStatus; import com.android.wm.shell.tests.R; import org.junit.Before; @@ -201,12 +206,8 @@ public class WindowDecorationTests extends ShellTestCase { createMockSurfaceControlBuilder(captionContainerSurface); mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder); - final ActivityManager.TaskDescription.Builder taskDescriptionBuilder = - new ActivityManager.TaskDescription.Builder() - .setBackgroundColor(Color.YELLOW); final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() .setDisplayId(Display.DEFAULT_DISPLAY) - .setTaskDescriptionBuilder(taskDescriptionBuilder) .setBounds(TASK_BOUNDS) .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y) .setVisible(true) @@ -255,8 +256,6 @@ public class WindowDecorationTests extends ShellTestCase { verify(mMockSurfaceControlFinishT).setCornerRadius(taskSurface, CORNER_RADIUS); verify(mMockSurfaceControlStartT) .show(taskSurface); - verify(mMockSurfaceControlStartT) - .setColor(taskSurface, new float[] {1.f, 1.f, 0.f}); verify(mMockSurfaceControlStartT).setShadowRadius(taskSurface, 10); assertEquals(300, mRelayoutResult.mWidth); @@ -502,6 +501,86 @@ public class WindowDecorationTests extends ShellTestCase { verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT); } + @Test + public void testRelayout_fluidResizeEnabled_freeformTask_setTaskSurfaceColor() { + StaticMockitoSession mockitoSession = mockitoSession().mockStatic( + DesktopModeStatus.class).strictness( + LENIENT).startMocking(); + when(DesktopModeStatus.isVeiledResizeEnabled()).thenReturn(false); + + final Display defaultDisplay = mock(Display.class); + doReturn(defaultDisplay).when(mMockDisplayController) + .getDisplay(Display.DEFAULT_DISPLAY); + + final SurfaceControl decorContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder decorContainerSurfaceBuilder = + createMockSurfaceControlBuilder(decorContainerSurface); + mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); + final SurfaceControl captionContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder captionContainerSurfaceBuilder = + createMockSurfaceControlBuilder(captionContainerSurface); + mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder); + + final ActivityManager.TaskDescription.Builder taskDescriptionBuilder = + new ActivityManager.TaskDescription.Builder() + .setBackgroundColor(Color.YELLOW); + + final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() + .setDisplayId(Display.DEFAULT_DISPLAY) + .setTaskDescriptionBuilder(taskDescriptionBuilder) + .setVisible(true) + .setWindowingMode(WINDOWING_MODE_FREEFORM) + .build(); + taskInfo.isFocused = true; + final SurfaceControl taskSurface = mock(SurfaceControl.class); + final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); + + windowDecor.relayout(taskInfo); + + verify(mMockSurfaceControlStartT).setColor(taskSurface, new float[] {1.f, 1.f, 0.f}); + + mockitoSession.finishMocking(); + } + + @Test + public void testRelayout_fluidResizeEnabled_fullscreenTask_clearTaskSurfaceColor() { + StaticMockitoSession mockitoSession = mockitoSession().mockStatic( + DesktopModeStatus.class).strictness(LENIENT).startMocking(); + when(DesktopModeStatus.isVeiledResizeEnabled()).thenReturn(false); + + final Display defaultDisplay = mock(Display.class); + doReturn(defaultDisplay).when(mMockDisplayController) + .getDisplay(Display.DEFAULT_DISPLAY); + + final SurfaceControl decorContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder decorContainerSurfaceBuilder = + createMockSurfaceControlBuilder(decorContainerSurface); + mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); + final SurfaceControl captionContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder captionContainerSurfaceBuilder = + createMockSurfaceControlBuilder(captionContainerSurface); + mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder); + + final ActivityManager.TaskDescription.Builder taskDescriptionBuilder = + new ActivityManager.TaskDescription.Builder() + .setBackgroundColor(Color.YELLOW); + final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() + .setDisplayId(Display.DEFAULT_DISPLAY) + .setTaskDescriptionBuilder(taskDescriptionBuilder) + .setVisible(true) + .setWindowingMode(WINDOWING_MODE_FULLSCREEN) + .build(); + taskInfo.isFocused = true; + final SurfaceControl taskSurface = mock(SurfaceControl.class); + final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); + + windowDecor.relayout(taskInfo); + + verify(mMockSurfaceControlStartT).unsetColor(taskSurface); + + mockitoSession.finishMocking(); + } + private TestWindowDecoration createWindowDecoration( ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) { return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer, diff --git a/libs/dream/lowlight/tests/Android.bp b/libs/dream/lowlight/tests/Android.bp index 64b53cbb5c5a..4dafd0aa6df4 100644 --- a/libs/dream/lowlight/tests/Android.bp +++ b/libs/dream/lowlight/tests/Android.bp @@ -34,7 +34,7 @@ android_test { "mockito-target-extended-minus-junit4", "platform-test-annotations", "testables", - "truth-prebuilt", + "truth", ], libs: [ "android.test.mock", diff --git a/libs/securebox/tests/Android.bp b/libs/securebox/tests/Android.bp index 7df546ae0ff6..80b501da1aa5 100644 --- a/libs/securebox/tests/Android.bp +++ b/libs/securebox/tests/Android.bp @@ -32,7 +32,7 @@ android_test { "platform-test-annotations", "testables", "testng", - "truth-prebuilt", + "truth", ], libs: [ "android.test.mock", diff --git a/media/java/android/media/RingtoneSelection.java b/media/java/android/media/RingtoneSelection.java index 74f72767c3f8..b74b6a3dbac9 100644 --- a/media/java/android/media/RingtoneSelection.java +++ b/media/java/android/media/RingtoneSelection.java @@ -18,16 +18,23 @@ package android.media; 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.TestApi; +import android.content.ContentProvider; import android.content.ContentResolver; import android.net.Uri; +import android.os.UserHandle; +import android.os.vibrator.Flags; import android.provider.MediaStore; +import com.android.internal.annotations.VisibleForTesting; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Objects; /** * Immutable representation a desired ringtone, usually originating from a user preference. @@ -46,7 +53,7 @@ import java.lang.annotation.RetentionPolicy; * to be internally consistent and reflect effective values - with the exception of not verifying * the actual URI content. For example, loading a selection Uri that sets a sound source to * {@link #SOUND_SOURCE_URI}, but doesn't also have a sound Uri set, will result in this class - * instead returning {@link #SOUND_SOURCE_DEFAULT} from {@link #getSoundSource}. + * instead returning {@link #SOUND_SOURCE_UNSPECIFIED} from {@link #getSoundSource}. * * <h2>Storing preferences</h2> * @@ -57,6 +64,7 @@ import java.lang.annotation.RetentionPolicy; * @hide */ @TestApi +@FlaggedApi(Flags.FLAG_HAPTICS_CUSTOMIZATION_ENABLED) public final class RingtoneSelection { /** @@ -70,7 +78,7 @@ public final class RingtoneSelection { * The sound source is not explicitly specified, so it can follow default behavior for its * context. */ - public static final int SOUND_SOURCE_DEFAULT = 0; + public static final int SOUND_SOURCE_UNSPECIFIED = 0; /** * Sound is explicitly disabled, such as the user having selected "Silent" in the sound picker. @@ -83,15 +91,25 @@ public final class RingtoneSelection { public static final int SOUND_SOURCE_URI = 2; /** + * The sound should explicitly use the system default. + * + * <p>This value isn't valid within the system default itself. + */ + public static final int SOUND_SOURCE_SYSTEM_DEFAULT = 3; + + // Note: Value 4 reserved for possibility of SOURCE_SOURCE_APPLICATION_DEFAULT. + + /** * Directive for how to make sound. * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "SOUND_SOURCE_", value = { SOUND_SOURCE_UNKNOWN, - SOUND_SOURCE_DEFAULT, + SOUND_SOURCE_UNSPECIFIED, SOUND_SOURCE_OFF, SOUND_SOURCE_URI, + SOUND_SOURCE_SYSTEM_DEFAULT, }) public @interface SoundSource {} @@ -106,9 +124,9 @@ public final class RingtoneSelection { /** * Vibration source is not explicitly specified. If vibration is enabled, this will use the * first available of {@link #VIBRATION_SOURCE_AUDIO_CHANNEL}, - * {@link #VIBRATION_SOURCE_APPLICATION_PROVIDED}, or system default vibration. + * {@link #VIBRATION_SOURCE_APPLICATION_DEFAULT}, or {@link #VIBRATION_SOURCE_SYSTEM_DEFAULT}. */ - public static final int VIBRATION_SOURCE_DEFAULT = 0; + public static final int VIBRATION_SOURCE_UNSPECIFIED = 0; /** Specifies that vibration is explicitly disabled for this ringtone. */ public static final int VIBRATION_SOURCE_OFF = 1; @@ -117,22 +135,31 @@ public final class RingtoneSelection { public static final int VIBRATION_SOURCE_URI = 2; /** + * The vibration should explicitly use the system default. + * + * <p>This value isn't valid within the system default itself. + */ + public static final int VIBRATION_SOURCE_SYSTEM_DEFAULT = 3; + + /** * Specifies that vibration should use the vibration provided by the application. This is * typically the application's own default for the use-case, provided via * {@link Ringtone.Builder#setVibrationEffect}. For notification channels, this is the vibration * effect saved on the notification channel. * * <p>If no vibration is specified by the application, this value behaves if the source was - * {@link #VIBRATION_SOURCE_DEFAULT}. + * {@link #VIBRATION_SOURCE_UNSPECIFIED}. + * + * <p>This value isn't valid within the system default. */ - public static final int VIBRATION_SOURCE_APPLICATION_PROVIDED = 3; + public static final int VIBRATION_SOURCE_APPLICATION_DEFAULT = 4; /** * Specifies that vibration should use haptic audio channels from the * sound Uri. If the sound URI doesn't have haptic channels, then reverts to the order specified - * by {@link #VIBRATION_SOURCE_DEFAULT}. + * by {@link #VIBRATION_SOURCE_UNSPECIFIED}. */ - // Numeric gap from VIBRATION_SOURCE_APPLICATION_PROVIDED in case we want other common elements. + // Numeric gap from VIBRATION_SOURCE_APPLICATION_DEFAULT in case we want other common elements. public static final int VIBRATION_SOURCE_AUDIO_CHANNEL = 10; /** @@ -151,10 +178,10 @@ public final class RingtoneSelection { @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "VIBRATION_SOURCE_", value = { VIBRATION_SOURCE_UNKNOWN, - VIBRATION_SOURCE_DEFAULT, + VIBRATION_SOURCE_UNSPECIFIED, VIBRATION_SOURCE_OFF, VIBRATION_SOURCE_URI, - VIBRATION_SOURCE_APPLICATION_PROVIDED, + VIBRATION_SOURCE_APPLICATION_DEFAULT, VIBRATION_SOURCE_AUDIO_CHANNEL, VIBRATION_SOURCE_HAPTIC_GENERATOR, }) @@ -162,9 +189,12 @@ public final class RingtoneSelection { /** * Configures {@link #RingtoneSelection#fromUri} to treat an unrecognized Uri as the sound Uri - * for the returned {@link RingtoneSelection}, with null meaning {@link #SOUND_SOURCE_OFF}. - * This behavior is particularly suited to loading values from older settings that may contain - * a raw sound Uri or null for silent. + * for the returned {@link RingtoneSelection}, with null meaning {@link #SOUND_SOURCE_OFF}, + * and symbolic default URIs ({@link RingtoneManager#getDefaultUri}) meaning + * {@link #SOUND_SOURCE_SYSTEM_DEFAULT}. + * + * <p>This behavior is particularly suited to loading values from older settings that may + * contain a raw sound Uri or null for silent. * * <p>An unrecognized Uri is one for which {@link #isRingtoneSelectionUri(Uri)} returns false. */ @@ -173,7 +203,8 @@ public final class RingtoneSelection { /** * Configures {@link #RingtoneSelection#fromUri} to treat an unrecognized Uri as the vibration * Uri for the returned {@link RingtoneSelection}, with null meaning - * {@link #VIBRATION_SOURCE_OFF}. + * {@link #VIBRATION_SOURCE_OFF} and symbolic default URIs + * ({@link RingtoneManager#getDefaultUri}) meaning {@link #VIBRATION_SOURCE_SYSTEM_DEFAULT}. * * <p>An unrecognized Uri is one for which {@link #isRingtoneSelectionUri(Uri)} returns false. */ @@ -182,7 +213,9 @@ public final class RingtoneSelection { /** * Configures {@link #RingtoneSelection#fromUri} to treat an unrecognized Uri as an invalid * value. Null or an invalid values will revert to default behavior correspnoding to - * {@link #DEFAULT_SELECTION_URI_STRING}. + * {@link #DEFAULT_SELECTION_URI_STRING}. Symbolic default URIs + * ({@link RingtoneManager#getDefaultUri}) will set both + * {@link #SOUND_SOURCE_SYSTEM_DEFAULT} and {@link #VIBRATION_SOURCE_SYSTEM_DEFAULT}. * * <p>An unrecognized Uri is one for which {@link #isRingtoneSelectionUri(Uri)} returns false, * which include {@code null}. @@ -218,10 +251,11 @@ public final class RingtoneSelection { /* Common param values */ private static final String SOURCE_OFF_STRING = "off"; + private static final String SOURCE_SYSTEM_DEFAULT_STRING = "sys"; /* Vibration source param values. */ private static final String VIBRATION_SOURCE_AUDIO_CHANNEL_STRING = "ac"; - private static final String VIBRATION_SOURCE_APPLICATION_PROVIDED_STRING = "app"; + private static final String VIBRATION_SOURCE_APPLICATION_DEFAULT_STRING = "app"; private static final String VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING = "hg"; @Nullable @@ -236,53 +270,45 @@ public final class RingtoneSelection { private RingtoneSelection(@Nullable Uri soundUri, @SoundSource int soundSource, @Nullable Uri vibrationUri, @VibrationSource int vibrationSource) { - // Enforce guarantees on the source values: revert to unset if they depend on something - // that's not set. - switch (soundSource) { - case SOUND_SOURCE_URI: - case SOUND_SOURCE_UNKNOWN: // Allow unknown to revert to URI before default. - mSoundSource = soundUri != null ? SOUND_SOURCE_URI : SOUND_SOURCE_DEFAULT; - break; - default: - mSoundSource = soundSource; - break; - } - switch (vibrationSource) { - case VIBRATION_SOURCE_AUDIO_CHANNEL: - case VIBRATION_SOURCE_HAPTIC_GENERATOR: - mVibrationSource = soundUri != null ? vibrationSource : VIBRATION_SOURCE_DEFAULT; - break; - case VIBRATION_SOURCE_URI: - case VIBRATION_SOURCE_UNKNOWN: // Allow unknown to revert to URI. - mVibrationSource = - vibrationUri != null ? VIBRATION_SOURCE_URI : VIBRATION_SOURCE_DEFAULT; - break; - default: - mVibrationSource = vibrationSource; - break; - } + // Enforce guarantees on the source values: revert to unspecified if they depend on + // something that's not set. + // + // The non-public "unknown" value can't appear in a getter result, it's just a reserved + // "null" value and should be treated the same as an unrecognized value. This can be seen + // in Uri parsing. For this and other unrecognized values, we either revert them to the URI + // source, if a Uri was included, or the "unspecified" source otherwise. This can be + // seen in action in the Uri parsing. + // + // The "unspecified" source is a public value meaning that there is no specific + // behavior indicated, and the defaults and fallbacks should be applied. For example, an + // vibration source value of "system default" means to explicitly use the system default + // vibration. However, an "unspecified" vibration source will first see if audio coupled + // or application-default vibrations are available. + mSoundSource = switch (soundSource) { + // Supported explicit values that don't have a Uri. + case SOUND_SOURCE_OFF, SOUND_SOURCE_UNSPECIFIED, SOUND_SOURCE_SYSTEM_DEFAULT -> + soundSource; + // Uri and unknown/unrecognized values: use a Uri if one is present, else revert to + // unspecified. + default -> + soundUri != null ? SOUND_SOURCE_URI : SOUND_SOURCE_UNSPECIFIED; + }; + mVibrationSource = switch (vibrationSource) { + // Enforce vibration sources that require a sound Uri. + case VIBRATION_SOURCE_AUDIO_CHANNEL, VIBRATION_SOURCE_HAPTIC_GENERATOR -> + soundUri != null ? vibrationSource : VIBRATION_SOURCE_UNSPECIFIED; + // Supported explicit values that don't rely on any Uri. + case VIBRATION_SOURCE_OFF, VIBRATION_SOURCE_UNSPECIFIED, + VIBRATION_SOURCE_SYSTEM_DEFAULT, VIBRATION_SOURCE_APPLICATION_DEFAULT -> + vibrationSource; + // Uri and unknown/unrecognized values: use a Uri if one is present, else revert to + // unspecified. + default -> + vibrationUri != null ? VIBRATION_SOURCE_URI : VIBRATION_SOURCE_UNSPECIFIED; + }; // Clear Uri values if they're un-used by the source. - switch (mSoundSource) { - case SOUND_SOURCE_OFF: - mSoundUri = null; - break; - default: - // Unset case isn't handled here: the defaulting behavior is left to the player. - mSoundUri = soundUri; - break; - } - switch (mVibrationSource) { - case VIBRATION_SOURCE_OFF: - case VIBRATION_SOURCE_APPLICATION_PROVIDED: - case VIBRATION_SOURCE_AUDIO_CHANNEL: - case VIBRATION_SOURCE_HAPTIC_GENERATOR: - mVibrationUri = null; - break; - default: - // Unset case isn't handled here: the defaulting behavior is left to the player. - mVibrationUri = vibrationUri; - break; - } + mSoundUri = mSoundSource == SOUND_SOURCE_URI ? soundUri : null; + mVibrationUri = mVibrationSource == VIBRATION_SOURCE_URI ? vibrationUri : null; } /** @@ -360,18 +386,83 @@ public final class RingtoneSelection { } // Any URI content://media/ringtone return ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()) - && MediaStore.AUTHORITY.equals(uri.getAuthority()) + && MediaStore.AUTHORITY.equals( + ContentProvider.getAuthorityWithoutUserId(uri.getAuthority())) && MEDIA_URI_RINGTONE_PATH.equals(uri.getPath()); } + /** + * Strip the specified userId from internal Uris. Non-stripped userIds will typically be + * for work profiles referencing system ringtones from the host user. + * + * This is only for use in RingtoneManager. + * @hide + */ + @VisibleForTesting + public RingtoneSelection getWithoutUserId(int userIdToStrip) { + if (mSoundSource != SOUND_SOURCE_URI && mVibrationSource != VIBRATION_SOURCE_URI) { + return this; + } + // Ok if uri is null. We only replace explicit references to the specified (current) userId. + int soundUserId = ContentProvider.getUserIdFromUri(mSoundUri, UserHandle.USER_NULL); + int vibrationUserId = ContentProvider.getUserIdFromUri(mVibrationUri, UserHandle.USER_NULL); + boolean needToChangeSound = + soundUserId != UserHandle.USER_NULL && soundUserId == userIdToStrip; + boolean needToChangeVibration = + vibrationUserId != UserHandle.USER_NULL && vibrationUserId == userIdToStrip; + + // Anything to do? + if (!needToChangeSound && !needToChangeVibration) { + return this; + } + + RingtoneSelection.Builder updated = new Builder(this); + // The relevant uris can't be null, because they contain userIdToStrip. + if (needToChangeSound) { + // mSoundUri is not null, so the result of getUriWithoutUserId won't be null. + updated.setSoundSource(ContentProvider.getUriWithoutUserId(mSoundUri)); + } + if (needToChangeVibration) { + updated.setVibrationSource(ContentProvider.getUriWithoutUserId(mVibrationUri)); + } + return updated.build(); + } + + @Override + public String toString() { + return toUri().toString(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof RingtoneSelection other)) { + return false; + } + return this.mSoundSource == other.mSoundSource + && this.mVibrationSource == other.mVibrationSource + && Objects.equals(this.mSoundUri, other.mSoundUri) + && Objects.equals(this.mVibrationUri, other.mVibrationUri); + } + + @Override + public int hashCode() { + return Objects.hash(mSoundSource, mVibrationSource, mSoundUri, mVibrationUri); + } /** * Converts a Uri into a RingtoneSelection. * - * <p>Null values and Uris that {@link #isRingtoneSelectionUri(Uri)} returns false will be - * treated according to the behaviour specified by the {@code unrecognizedValueBehavior} - * parameter. + * <p>Null values, Uris that {@link #isRingtoneSelectionUri(Uri)} returns false (except for + * old-style symbolic default Uris {@link RingtoneManager#getDefaultUri}) will be treated + * according to the behaviour specified by the {@code unrecognizedValueBehavior} parameter. + * + * <p>Symbolic default Uris (where {@link RingtoneManager#getDefaultType(Uri)} returns -1, + * will map sources to {@link #SOUND_SOURCE_SYSTEM_DEFAULT} and + * {@link #VIBRATION_SOURCE_SYSTEM_DEFAULT}. * * @param uri The Uri to convert, potentially null. * @param unrecognizedValueBehavior indicates how to treat values for which @@ -384,21 +475,35 @@ public final class RingtoneSelection { if (isRingtoneSelectionUri(uri)) { return parseRingtoneSelectionUri(uri); } + // Old symbolic default URIs map to the sources suggested by the unrecognized behavior. + // It doesn't always map to both sources because the app may have its own default behavior + // to apply, so non-primary sources are left as unspecified, which will revert to the + // system default in the absence of an app default. + boolean isDefaultUri = RingtoneManager.getDefaultType(uri) > 0; RingtoneSelection.Builder builder = new RingtoneSelection.Builder(); switch (unrecognizedValueBehavior) { case FROM_URI_RINGTONE_SELECTION_ONLY: - // Always return use-defaults for unrecognized ringtone selection Uris. + if (isDefaultUri) { + builder.setSoundSource(SOUND_SOURCE_SYSTEM_DEFAULT); + builder.setVibrationSource(VIBRATION_SOURCE_SYSTEM_DEFAULT); + } + // Always return unspecified (defaults) for unrecognized ringtone selection Uris. return builder.build(); case FROM_URI_RINGTONE_SELECTION_OR_SOUND: if (uri == null) { return builder.setSoundSource(SOUND_SOURCE_OFF).build(); + } else if (isDefaultUri) { + return builder.setSoundSource(SOUND_SOURCE_SYSTEM_DEFAULT).build(); } else { return builder.setSoundSource(uri).build(); } case FROM_URI_RINGTONE_SELECTION_OR_VIBRATION: if (uri == null) { return builder.setVibrationSource(VIBRATION_SOURCE_OFF).build(); + } else if (isDefaultUri) { + return builder.setVibrationSource(VIBRATION_SOURCE_SYSTEM_DEFAULT).build(); } else { + // Unlike sound, there's no legacy settings alias uri for the default. return builder.setVibrationSource(uri).build(); } default: @@ -407,7 +512,12 @@ public final class RingtoneSelection { } } - /** Parses the Uri, which has already been checked for {@link #isRingtoneSelectionUri(Uri)}. */ + /** + * Parses the Uri, which has already been checked for {@link #isRingtoneSelectionUri(Uri)}. + * As a special case to be more compatible, if the RingtoneSelection has a userId specified in + * the authority, then this is pushed down into the sound and vibration Uri, as the selection + * itself is agnostic. + */ @NonNull private static RingtoneSelection parseRingtoneSelectionUri(@NonNull Uri uri) { RingtoneSelection.Builder builder = new RingtoneSelection.Builder(); @@ -416,19 +526,39 @@ public final class RingtoneSelection { uri.getQueryParameter(URI_PARAM_VIBRATION_SOURCE)); Uri soundUri = getParamAsUri(uri, URI_PARAM_SOUND_URI); Uri vibrationUri = getParamAsUri(uri, URI_PARAM_VIBRATION_URI); + + // Add userId if necessary. This won't override an existing one in the sound/vib Uris. + int userIdFromAuthority = ContentProvider.getUserIdFromAuthority( + uri.getAuthority(), UserHandle.USER_NULL); + if (userIdFromAuthority != UserHandle.USER_NULL) { + // Won't override existing user id. + if (soundUri != null) { + soundUri = ContentProvider.maybeAddUserId(soundUri, userIdFromAuthority); + } + if (vibrationUri != null) { + vibrationUri = ContentProvider.maybeAddUserId(vibrationUri, userIdFromAuthority); + } + } + + // Set sound uri if present, but map system default Uris to the system default source. if (soundUri != null) { - builder.setSoundSource(soundUri); + if (RingtoneManager.getDefaultType(uri) >= 0) { + builder.setSoundSource(SOUND_SOURCE_SYSTEM_DEFAULT); + } else { + builder.setSoundSource(soundUri); + } } if (vibrationUri != null) { builder.setVibrationSource(vibrationUri); } + // Don't set the source if there's a URI and the source is default, because that will // override the Uri source set above. In effect, we prioritise "explicit" sources over // an implicit Uri source - except for "default", which isn't really explicit. - if (soundSource != SOUND_SOURCE_DEFAULT || soundUri == null) { + if (soundSource != SOUND_SOURCE_UNSPECIFIED || soundUri == null) { builder.setSoundSource(soundSource); } - if (vibrationSource != VIBRATION_SOURCE_DEFAULT || vibrationUri == null) { + if (vibrationSource != VIBRATION_SOURCE_UNSPECIFIED || vibrationUri == null) { builder.setVibrationSource(vibrationSource); } return builder.build(); @@ -450,26 +580,28 @@ public final class RingtoneSelection { */ @Nullable private static String soundSourceToString(@SoundSource int soundSource) { - switch (soundSource) { - case SOUND_SOURCE_OFF: return SOURCE_OFF_STRING; - default: return null; - } + return switch (soundSource) { + case SOUND_SOURCE_OFF -> SOURCE_OFF_STRING; + case SOUND_SOURCE_SYSTEM_DEFAULT -> SOURCE_SYSTEM_DEFAULT_STRING; + default -> null; + }; } /** * Returns the sound source int corresponding to the query string value. Returns * {@link #SOUND_SOURCE_UNKNOWN} if the value isn't recognised, and - * {@link #SOUND_SOURCE_DEFAULT} if the value is {@code null} (not in the Uri). + * {@link #SOUND_SOURCE_UNSPECIFIED} if the value is {@code null} (not in the Uri). */ @SoundSource private static int stringToSoundSource(@Nullable String soundSource) { if (soundSource == null) { - return SOUND_SOURCE_DEFAULT; - } - switch (soundSource) { - case SOURCE_OFF_STRING: return SOUND_SOURCE_OFF; - default: return SOUND_SOURCE_UNKNOWN; + return SOUND_SOURCE_UNSPECIFIED; } + return switch (soundSource) { + case SOURCE_OFF_STRING -> SOUND_SOURCE_OFF; + case SOURCE_SYSTEM_DEFAULT_STRING -> SOUND_SOURCE_SYSTEM_DEFAULT; + default -> SOUND_SOURCE_UNKNOWN; + }; } /** @@ -478,30 +610,31 @@ public final class RingtoneSelection { */ @Nullable private static String vibrationSourceToString(@VibrationSource int vibrationSource) { - switch (vibrationSource) { - case VIBRATION_SOURCE_OFF: return SOURCE_OFF_STRING; - case VIBRATION_SOURCE_AUDIO_CHANNEL: return VIBRATION_SOURCE_AUDIO_CHANNEL_STRING; - case VIBRATION_SOURCE_HAPTIC_GENERATOR: - return VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING; - case VIBRATION_SOURCE_APPLICATION_PROVIDED: - return VIBRATION_SOURCE_APPLICATION_PROVIDED_STRING; - default: return null; - } + return switch (vibrationSource) { + case VIBRATION_SOURCE_OFF -> SOURCE_OFF_STRING; + case VIBRATION_SOURCE_AUDIO_CHANNEL -> VIBRATION_SOURCE_AUDIO_CHANNEL_STRING; + case VIBRATION_SOURCE_HAPTIC_GENERATOR -> VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING; + case VIBRATION_SOURCE_APPLICATION_DEFAULT -> + VIBRATION_SOURCE_APPLICATION_DEFAULT_STRING; + case VIBRATION_SOURCE_SYSTEM_DEFAULT -> SOURCE_SYSTEM_DEFAULT_STRING; + default -> null; + }; } @VibrationSource private static int stringToVibrationSource(@Nullable String vibrationSource) { if (vibrationSource == null) { - return VIBRATION_SOURCE_DEFAULT; - } - switch (vibrationSource) { - case SOURCE_OFF_STRING: return VIBRATION_SOURCE_OFF; - case VIBRATION_SOURCE_AUDIO_CHANNEL_STRING: return VIBRATION_SOURCE_AUDIO_CHANNEL; - case VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING: return VIBRATION_SOURCE_HAPTIC_GENERATOR; - case VIBRATION_SOURCE_APPLICATION_PROVIDED_STRING: - return VIBRATION_SOURCE_APPLICATION_PROVIDED; - default: return VIBRATION_SOURCE_UNKNOWN; + return VIBRATION_SOURCE_UNSPECIFIED; } + return switch (vibrationSource) { + case SOURCE_OFF_STRING -> VIBRATION_SOURCE_OFF; + case SOURCE_SYSTEM_DEFAULT_STRING -> VIBRATION_SOURCE_SYSTEM_DEFAULT; + case VIBRATION_SOURCE_AUDIO_CHANNEL_STRING -> VIBRATION_SOURCE_AUDIO_CHANNEL; + case VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING -> VIBRATION_SOURCE_HAPTIC_GENERATOR; + case VIBRATION_SOURCE_APPLICATION_DEFAULT_STRING -> + VIBRATION_SOURCE_APPLICATION_DEFAULT; + default -> VIBRATION_SOURCE_UNKNOWN; + }; } /** @@ -512,12 +645,13 @@ public final class RingtoneSelection { public static final class Builder { private Uri mSoundUri; private Uri mVibrationUri; - @SoundSource private int mSoundSource = SOUND_SOURCE_DEFAULT; - @VibrationSource private int mVibrationSource = VIBRATION_SOURCE_DEFAULT; + @SoundSource private int mSoundSource = SOUND_SOURCE_UNSPECIFIED; + @VibrationSource private int mVibrationSource = VIBRATION_SOURCE_UNSPECIFIED; /** * Creates a new {@link RingtoneSelection} builder. A default ringtone selection has its - * sound and vibration source unset, which means they would fall back to system defaults. + * sound and vibration source unspecified, which means they would fall back to app/system + * defaults. */ public Builder() {} @@ -559,7 +693,9 @@ public final class RingtoneSelection { */ @NonNull public Builder setSoundSource(@NonNull Uri soundUri) { - mSoundUri = requireNonNull(soundUri); + // getCanonicalUri shouldn't return null. If it somehow did, then the + // RingtoneSelection constructor will revert this to unspecified. + mSoundUri = requireNonNull(soundUri).getCanonicalUri(); mSoundSource = SOUND_SOURCE_URI; return this; } @@ -587,7 +723,9 @@ public final class RingtoneSelection { */ @NonNull public Builder setVibrationSource(@NonNull Uri vibrationUri) { - mVibrationUri = requireNonNull(vibrationUri); + // getCanonicalUri shouldn't return null. If it somehow did, then the + // RingtoneSelection constructor will revert this to unspecified. + mVibrationUri = requireNonNull(vibrationUri).getCanonicalUri(); mVibrationSource = VIBRATION_SOURCE_URI; return this; } diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig index 83d2b613f80a..a354f9180e09 100644 --- a/media/java/android/media/flags/media_better_together.aconfig +++ b/media/java/android/media/flags/media_better_together.aconfig @@ -15,8 +15,15 @@ flag { } flag { - namespace: "media_solutions" - name: "enable_audio_policies_device_and_bluetooth_controller" - description: "Use Audio Policies implementation for device and Bluetooth route controllers." - bug: "280576228" + namespace: "media_solutions" + name: "enable_audio_policies_device_and_bluetooth_controller" + description: "Use Audio Policies implementation for device and Bluetooth route controllers." + bug: "280576228" +} + +flag { + namespace: "media_solutions" + name: "disable_screen_off_broadcast_receiver" + description: "Disables the broadcast receiver that prevents scanning when the screen is off." + bug: "304234628" } diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp index ca20225e8885..bdd7afeb2f65 100644 --- a/media/tests/MediaFrameworkTest/Android.bp +++ b/media/tests/MediaFrameworkTest/Android.bp @@ -22,7 +22,7 @@ android_test { "android-ex-camera2", "testables", "testng", - "truth-prebuilt", + "truth", ], jni_libs: [ "libdexmakerjvmtiagent", diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp index 4cccf8972798..61b18c88e734 100644 --- a/media/tests/MediaRouter/Android.bp +++ b/media/tests/MediaRouter/Android.bp @@ -24,7 +24,7 @@ android_test { "compatibility-device-util-axt", "mockito-target-minus-junit4", "testng", - "truth-prebuilt", + "truth", ], test_suites: ["general-tests"], platform_apis: true, diff --git a/media/tests/projection/Android.bp b/media/tests/projection/Android.bp index e313c46d1973..48cd8b69ade8 100644 --- a/media/tests/projection/Android.bp +++ b/media/tests/projection/Android.bp @@ -30,7 +30,7 @@ android_test { "platform-test-annotations", "testng", "testables", - "truth-prebuilt", + "truth", "platform-compat-test-rules", ], diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt index ba88484518aa..2318bb95dabb 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt @@ -18,21 +18,23 @@ package com.android.credentialmanager.autofill import android.app.assist.AssistStructure import android.content.Context -import android.credentials.GetCredentialRequest import android.credentials.CredentialManager -import android.credentials.GetCandidateCredentialsResponse import android.credentials.CredentialOption import android.credentials.GetCandidateCredentialsException +import android.credentials.GetCandidateCredentialsResponse +import android.credentials.GetCredentialRequest import android.os.Bundle import android.os.CancellationSignal import android.os.OutcomeReceiver -import android.service.autofill.FillRequest import android.service.autofill.AutofillService -import android.service.autofill.FillResponse import android.service.autofill.FillCallback -import android.service.autofill.SaveRequest +import android.service.autofill.FillRequest +import android.service.autofill.FillResponse import android.service.autofill.SaveCallback +import android.service.autofill.SaveRequest +import android.service.credentials.CredentialProviderService import android.util.Log +import android.view.autofill.AutofillId import org.json.JSONObject import java.util.concurrent.Executors @@ -129,27 +131,31 @@ class CredentialAutofillService : AutofillService() { } private fun traverseNode( - viewNode: AssistStructure.ViewNode?, + viewNode: AssistStructure.ViewNode, cmRequests: MutableList<CredentialOption> ) { - val options = getCredentialOptionsFromViewNode(viewNode) - cmRequests.addAll(options) + viewNode.autofillId?.let { + val options = getCredentialOptionsFromViewNode(viewNode, it) + cmRequests.addAll(options) + } - val children: List<AssistStructure.ViewNode>? = - viewNode?.run { + val children: List<AssistStructure.ViewNode> = + viewNode.run { (0 until childCount).map { getChildAt(it) } } - children?.forEach { childNode: AssistStructure.ViewNode -> + children.forEach { childNode: AssistStructure.ViewNode -> traverseNode(childNode, cmRequests) } } - private fun getCredentialOptionsFromViewNode(viewNode: AssistStructure.ViewNode?): - List<CredentialOption> { + private fun getCredentialOptionsFromViewNode( + viewNode: AssistStructure.ViewNode, + autofillId: AutofillId + ): List<CredentialOption> { // TODO(b/293945193) Replace with isCredential check from viewNode val credentialHints: MutableList<String> = mutableListOf() - if (viewNode != null && viewNode.autofillHints != null) { + if (viewNode.autofillHints != null) { for (hint in viewNode.autofillHints!!) { if (hint.startsWith(CRED_HINT_PREFIX)) { credentialHints.add(hint.substringAfter(CRED_HINT_PREFIX)) @@ -159,12 +165,14 @@ class CredentialAutofillService : AutofillService() { val credentialOptions: MutableList<CredentialOption> = mutableListOf() for (credentialHint in credentialHints) { - convertJsonToCredentialOption(credentialHint).let { credentialOptions.addAll(it) } + convertJsonToCredentialOption(credentialHint, autofillId) + .let { credentialOptions.addAll(it) } } return credentialOptions } - private fun convertJsonToCredentialOption(jsonString: String): List<CredentialOption> { + private fun convertJsonToCredentialOption(jsonString: String, autofillId: AutofillId): + List<CredentialOption> { // TODO(b/302000646) Move this logic to jetpack so that is consistent // with building the json val credentialOptions: MutableList<CredentialOption> = mutableListOf() @@ -173,11 +181,14 @@ class CredentialAutofillService : AutofillService() { val options = json.getJSONArray(CRED_OPTIONS_KEY) for (i in 0 until options.length()) { val option = options.getJSONObject(i) - + val candidateBundle = convertJsonToBundle(option.getJSONObject(CANDIDATE_DATA_KEY)) + candidateBundle.putParcelable( + CredentialProviderService.EXTRA_AUTOFILL_ID, + autofillId) credentialOptions.add(CredentialOption( option.getString(TYPE_KEY), convertJsonToBundle(option.getJSONObject(REQUEST_DATA_KEY)), - convertJsonToBundle(option.getJSONObject(CANDIDATE_DATA_KEY)), + candidateBundle, option.getBoolean(SYS_PROVIDER_REQ_KEY), )) } diff --git a/packages/ExternalStorageProvider/tests/Android.bp b/packages/ExternalStorageProvider/tests/Android.bp index 633f18610921..86c62ef299e4 100644 --- a/packages/ExternalStorageProvider/tests/Android.bp +++ b/packages/ExternalStorageProvider/tests/Android.bp @@ -25,7 +25,7 @@ android_test { static_libs: [ "androidx.test.rules", "mockito-target", - "truth-prebuilt", + "truth", ], certificate: "platform", diff --git a/packages/FusedLocation/Android.bp b/packages/FusedLocation/Android.bp index 64b4c54e74ad..61a82701d155 100644 --- a/packages/FusedLocation/Android.bp +++ b/packages/FusedLocation/Android.bp @@ -47,7 +47,7 @@ android_test { test_config: "test/AndroidTest.xml", srcs: [ "test/src/**/*.java", - "src/**/*.java", // include real sources because we're forced to test this directly + "src/**/*.java", // include real sources because we're forced to test this directly ], libs: [ "android.test.base", @@ -60,9 +60,9 @@ android_test { "androidx.test.ext.junit", "androidx.test.ext.truth", "mockito-target-minus-junit4", - "truth-prebuilt", + "truth", ], platform_apis: true, certificate: "platform", - test_suites: ["device-tests"] + test_suites: ["device-tests"], } diff --git a/packages/InputDevices/res/raw/keyboard_layout_brazilian.kcm b/packages/InputDevices/res/raw/keyboard_layout_brazilian.kcm index ad3199ff2dc8..d9338b1fdab7 100644 --- a/packages/InputDevices/res/raw/keyboard_layout_brazilian.kcm +++ b/packages/InputDevices/res/raw/keyboard_layout_brazilian.kcm @@ -337,7 +337,7 @@ key M { label: 'M' base: 'm' shift, capslock: 'M' - shift+capslock: 'n' + shift+capslock: 'm' } key COMMA { diff --git a/packages/InputDevices/res/raw/keyboard_layout_persian.kcm b/packages/InputDevices/res/raw/keyboard_layout_persian.kcm index 67449220b189..fc53cbad91db 100644 --- a/packages/InputDevices/res/raw/keyboard_layout_persian.kcm +++ b/packages/InputDevices/res/raw/keyboard_layout_persian.kcm @@ -12,9 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. - - -type FULL +type OVERLAY ### Basic QWERTY keys ### diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml index 88bb30b34ede..7f23f747090b 100644 --- a/packages/InputDevices/res/xml/keyboard_layouts.xml +++ b/packages/InputDevices/res/xml/keyboard_layouts.xml @@ -227,13 +227,6 @@ android:label="@string/keyboard_layout_turkish" android:keyboardLayout="@raw/keyboard_layout_turkish" android:keyboardLocale="tr-Latn" - android:keyboardLayoutType="qwerty" /> - - <keyboard-layout - android:name="keyboard_layout_turkish" - android:label="@string/keyboard_layout_turkish" - android:keyboardLayout="@raw/keyboard_layout_turkish" - android:keyboardLocale="tr-Latn" android:keyboardLayoutType="turkish_q" /> <keyboard-layout diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsTextFieldPassword.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsTextFieldPassword.kt index d0a61882593c..0757df347d68 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsTextFieldPassword.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsTextFieldPassword.kt @@ -29,8 +29,8 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag @@ -46,6 +46,7 @@ import com.android.settingslib.spa.framework.theme.SettingsTheme fun SettingsTextFieldPassword( value: String, label: String, + enabled: Boolean = true, onTextChange: (String) -> Unit, ) { var visibility by remember { mutableStateOf(false) } @@ -60,6 +61,7 @@ fun SettingsTextFieldPassword( keyboardType = KeyboardType.Password, imeAction = ImeAction.Send ), + enabled = enabled, trailingIcon = { Icon( imageVector = if (visibility) Icons.Outlined.VisibilityOff diff --git a/packages/SettingsLib/Spa/testutils/Android.bp b/packages/SettingsLib/Spa/testutils/Android.bp index 4031cd7f7a6f..639d1a7a7f55 100644 --- a/packages/SettingsLib/Spa/testutils/Android.bp +++ b/packages/SettingsLib/Spa/testutils/Android.bp @@ -31,7 +31,7 @@ android_library { "androidx.compose.ui_ui-test-manifest", "androidx.lifecycle_lifecycle-runtime-testing", "mockito-kotlin2", - "truth-prebuilt", + "truth", ], kotlincflags: [ "-Xjvm-default=all", diff --git a/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig b/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig index d1bcb5746414..4936f882f91e 100644 --- a/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig +++ b/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig @@ -5,4 +5,11 @@ flag { namespace: "media_solutions" description: "Gates whether to use a MediaRouter2-based implementation of InfoMediaManager, instead of the legacy MediaRouter2Manager-based implementation." bug: "192657812" +} + +flag { + name: "enable_tv_media_output_dialog" + namespace: "tv_system_ui" + description: "Gates all the changes for the tv specific media output dialog" + bug: "303205631" }
\ 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 53db19207947..afdb92b1bbab 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi twee stawe."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi drie stawe."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi-sein vol."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Gekoppel aan jou toestel."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Oop netwerk"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Veilige netwerk"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android-bedryfstelsel"</string> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index 77c9a970ce43..ea8491b2138c 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"ሁለት የWiFi አሞሌዎች።"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"ሦስት የWiFi አሞሌዎች።"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"የWiFi ምልክት ሙሉ ነው።"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"ከመሣሪያዎ ጋር ተገናኝቷል።"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"አውታረ መረብ ክፈት"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"ደህንነቱ የተጠበቀ አውታረ መረብ"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android ስርዓተ ክወና"</string> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index 30d011aa2b58..c29e6911396b 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"إشارة Wi-Fi تتكون من شريطين."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"إشارة Wi-Fi تتكون من ثلاثة أشرطة."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"إشارة Wi-Fi كاملة."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"تم الاتصال بجهازك."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"شبكة مفتوحة"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"شبكة محمية بكلمة مرور"</string> <string name="process_kernel_label" msgid="950292573930336765">"نظام التشغيل Android"</string> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index 31aff6a136f6..8eff4f6eba44 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"ৱাই-ফাইৰ দুডাল দণ্ড।"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"ৱাই-ফাইৰ তিনিডাল দণ্ড।"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"ৱাই-ফাই সংকেত সৰ্বোচ্চ।"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"আপোনাৰ ডিভাইচটোৰ সৈতে সংযোগ কৰা আছে।"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"মুক্ত নেটৱৰ্ক"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"সুৰক্ষিত নেটৱৰ্ক"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index c675ce797984..dfd1b7b83204 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi iki xətdir."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi üç xətdir."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi siqnalı tamdır."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Cihaza qoşuldu."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Açıq şəbəkə"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Təhlükəsiz şəbəkə"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index f7be60fe8be2..528e96e4c747 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WiFi signal ima dve crte."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WiFi signal ima tri crte."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WiFi signal je najjači."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Povezano je sa uređajem."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Otvorena mreža"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Bezbedna mreža"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index d2f2851f58a0..52614b7df160 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Два слупкi Wi-Fi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Тры слупкi Wi-Fi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Поўны сігнал Wi-Fi."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Устаноўлена падключэнне да прылады."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Адкрытая сетка"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Бяспечная сетка"</string> <string name="process_kernel_label" msgid="950292573930336765">"АС Android"</string> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index 2540c129dd53..b28ae6742f68 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi е с две чертички."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi е с три чертички."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Сигналът за Wi-Fi е пълен."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Установена е връзка с устройството ви."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Отворена мрежа"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Защитена мрежа"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android (ОС)"</string> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index 745b9446a1ab..c91f14ca2fad 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"ওয়াই ফাই এ দুইটি দণ্ড৷"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"ওয়াই ফাই এ তিনটি দণ্ড৷"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"ওয়াই ফাই এ সম্পূর্ণ সিগন্যাল৷"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"আপনার ডিভাইসের সাথে কানেক্ট করা হয়েছে।"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"খোলা নেটওয়ার্ক"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"সুরক্ষিত নেটওয়ার্ক"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index cab0841dd423..aa1073d74d40 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WiFi signal ima dvije crte."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WiFi signal ima tri crte."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WiFi signal je pun."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Povezani ste s uređajem."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Otvorena mreža"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sigurna mreža"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index a65b9c2b60d8..ab6393a7d407 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Senyal Wi-Fi: dues barres."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Senyal Wi-Fi: tres barres."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Senyal Wi-Fi: complet."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"S\'ha connectat al teu dispositiu."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Xarxa oberta"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Xarxa segura"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index 96c02aed1a65..e7d524317bae 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi – dvě čárky."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi – tři čárky."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi – plný signál."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Připojeno k vašemu zařízení."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Nezabezpečená síť"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Zabezpečená síť"</string> <string name="process_kernel_label" msgid="950292573930336765">"OS Android"</string> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index 1e4c7b7b04fb..1612ac030205 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi har to bjælker."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi har tre bjælker."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi har fuldt signal."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Der er oprettet forbindelse til din enhed."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Åbent netværk"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sikkert netværk"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index 37f7e5aa732a..73a44f140cbf 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WLAN: zwei Balken"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WLAN: drei Balken"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WLAN: volle Signalstärke"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Mit deinem Gerät verbunden."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Offenes Netzwerk"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sicheres Netzwerk"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index 84b8bf221c40..7dfd679ffacf 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Δύο γραμμές Wi-Fi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Τρεις γραμμές Wi-Fi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Άριστο σήμα Wi-Fi."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Συνδέθηκε στη συσκευή σας."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Ανοικτό δίκτυο"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Ασφαλές δίκτυο"</string> <string name="process_kernel_label" msgid="950292573930336765">"Λειτουργικό σύστημα Android"</string> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index 7298c022e702..aead40d12072 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi two bars."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi three bars."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi signal full."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Connected to your device."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Open network"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Secure network"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index 7298c022e702..aead40d12072 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi two bars."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi three bars."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi signal full."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Connected to your device."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Open network"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Secure network"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index 7298c022e702..aead40d12072 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi two bars."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi three bars."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi signal full."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Connected to your device."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Open network"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Secure network"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 86541fd5b294..291a68bc14fc 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Dos barras de Wi-Fi"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Tres barras de Wi-Fi"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Señal de Wi-Fi excelente"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Se estableció conexión con el dispositivo."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Red abierta"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Red segura"</string> <string name="process_kernel_label" msgid="950292573930336765">"SO Android"</string> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index ef9cc03421d2..b4bc31913902 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Dos barras de Wi-Fi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Tres barras de Wi-Fi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Señal de Wi-Fi al máximo."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Conectado a tu dispositivo."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Red abierta"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Red segura"</string> <string name="process_kernel_label" msgid="950292573930336765">"SO Android"</string> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index c8d806b21bd4..e5cbaf61fbb5 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WiFi: kaks pulka."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WiFi: kolm pulka."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WiFi-signaal on tugev."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Seadmega ühendatud."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Avatud võrk"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Turvaline võrk"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml index 95adf968af12..00f43a3bf51b 100644 --- a/packages/SettingsLib/res/values-eu/arrays.xml +++ b/packages/SettingsLib/res/values-eu/arrays.xml @@ -264,7 +264,7 @@ <string-array name="debug_hw_overdraw_entries"> <item msgid="1968128556747588800">"Desaktibatuta"</item> <item msgid="3033215374382962216">"Erakutsi gainidatzi diren eremuak"</item> - <item msgid="3474333938380896988">"Erakutsi daltonismorako eremuak"</item> + <item msgid="3474333938380896988">"Erakutsi deuteranomaliarako eremuak"</item> </string-array> <string-array name="app_process_limit_entries"> <item msgid="794656271086646068">"Muga estandarra"</item> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 7d76514f2ef0..90d45eb44fdc 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi sarearen bi barra."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi sarearen hiru barra."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi sarearen seinalea osoa."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Gailura konektatuta."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Sare irekia"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sare segurua"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android sistema eragilea"</string> @@ -368,7 +367,7 @@ <string name="debug_hw_overdraw" msgid="8944851091008756796">"Araztu GPU gainidazketa"</string> <string name="disable_overlays" msgid="4206590799671557143">"Desgaitu HW gainjartzeak"</string> <string name="disable_overlays_summary" msgid="1954852414363338166">"Erabili beti GPUa pantaila-muntaietarako"</string> - <string name="simulate_color_space" msgid="1206503300335835151">"Simulatu kolore-eremua"</string> + <string name="simulate_color_space" msgid="1206503300335835151">"Simulatu kolore-espazioa"</string> <string name="enable_opengl_traces_title" msgid="4638773318659125196">"Gaitu OpenGL aztarnak"</string> <string name="usb_audio_disable_routing" msgid="3367656923544254975">"Desgaitu USB bidez audioa bideratzeko aukera"</string> <string name="usb_audio_disable_routing_summary" msgid="8768242894849534699">"Desgaitu USB bidezko audio-gailuetara automatikoki bideratzeko aukera"</string> @@ -441,7 +440,7 @@ <string name="picture_color_mode_desc" msgid="151780973768136200">"Erabili sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Desgaituta"</string> <string name="daltonizer_mode_monochromacy" msgid="362060873835885014">"Ikusmen-monokromia"</string> - <string name="daltonizer_mode_deuteranomaly" msgid="3507284319584683963">"Daltonismoa (gorri-berdeak)"</string> + <string name="daltonizer_mode_deuteranomaly" msgid="3507284319584683963">"Deuteranomalia (gorri-berdeak)"</string> <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanopia (gorri-berdeak)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (urdin-horia)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Koloreen zuzenketa"</string> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index beb0b968b338..f3f97c460780 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"دو نوار برای Wi‑Fi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"سه نوار برای Wi‑Fi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"قدرت سیگنال Wi‑Fi کامل است."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"به دستگاهتان متصل شد."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"شبکه باز"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"شبکه ایمن"</string> <string name="process_kernel_label" msgid="950292573930336765">"سیستمعامل Android"</string> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index 88723162ae7d..7f3d0f286695 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi-signaali – kaksi palkkia"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi-signaali – kolme palkkia"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Vahva Wi-Fi-signaali"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Yhdistetty laitteeseesi."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Avoin verkko"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Suojattu verkko"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android-käyttöjärjestelmä"</string> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index 98e3753376e3..b7c3a81b47cd 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi : deux barres."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi : trois barres."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi : signal complet."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Connecté à votre appareil."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Réseau ouvert"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Réseau sécurisé"</string> <string name="process_kernel_label" msgid="950292573930336765">"Système d\'exploitation Android"</string> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 4a64041192a3..a9e0c6a5ccb5 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Signal Wi-Fi moyen"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Signal Wi-Fi bon"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Signal Wi-Fi excellent"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Connecté à votre appareil."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Réseau ouvert"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Réseau sécurisé"</string> <string name="process_kernel_label" msgid="950292573930336765">"OS Android"</string> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 26738e6f54e7..09c2969bac2d 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Dúas barras de wifi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Tres barras de wifi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Sinal completo de wifi."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Conexión establecida co teu dispositivo."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rede aberta"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rede segura"</string> <string name="process_kernel_label" msgid="950292573930336765">"SO Android"</string> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index b620d4184b8e..575c67510e89 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi બે બાર."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi ત્રણ બાર."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"પૂર્ણ Wifi સિગ્નલ."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"તમારા ડિવાઇસ સાથે કનેક્ટેડ છે."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"નેટવર્ક ખોલો"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"સુરક્ષિત નેટવર્ક"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 3811167c9c49..655fac041c9b 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"वाई-फ़ाई की दो पट्टी मिल रही हैं."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"वाई-फ़ाई की एक पट्टी मिल रही है."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"पूरे वाई-फ़ाई सिग्नल मिल रहे हैं."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"आपके डिवाइस से कनेक्ट हो गया है."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"खुला नेटवर्क"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"सुरक्षित नेटवर्क"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> @@ -598,7 +597,7 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"प्रोफ़ाइल की जानकारी"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"इससे पहले कि आप कोई प्रतिबंधित प्रोफ़ाइल बनाएं, आपको अपने ऐप्लिकेशन और व्यक्तिगत डेटा की सुरक्षा करने के लिए एक स्क्रीन लॉक सेट करना होगा."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"लॉक सेट करें"</string> - <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> पर जाएं"</string> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> पर स्विच करें"</string> <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नए उपयोगकर्ता को जोड़ा जा रहा है…"</string> <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"नया मेहमान खाता बनाया जा रहा है…"</string> <string name="add_user_failed" msgid="4809887794313944872">"नया उपयोगकर्ता जोड़ा नहीं जा सका"</string> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index 71a2daeb901c..f0e16a47346f 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi signal ima dva stupca."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi signal ima tri stupca."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi signal je pun."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Povezano s vašim uređajem."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Otvorena mreža"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sigurna mreža"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> @@ -619,7 +618,7 @@ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Time će se izbrisati aplikacije i podaci iz trenutačne gostujuće sesije."</string> <string name="grant_admin" msgid="4323199171790522574">"Da, dodijeli status administratora"</string> <string name="not_grant_admin" msgid="3557849576157702485">"Ne, nemoj dodijeliti status administratora"</string> - <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Izlaz"</string> + <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Izađi"</string> <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Želite li spremiti aktivnosti gosta?"</string> <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Možete spremiti aktivnosti iz ove sesije ili izbrisati sve aplikacije i podatke"</string> <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Izbriši"</string> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index 5fac75da75ab..420e0e969fd9 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi-jel: két sáv."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi-jel: három sáv."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi-jel: teljes."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Csatlakoztatva az eszközhöz."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Nyílt hálózat"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Biztonságos hálózat"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index e40c5e164110..705fcf6637b2 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi-ի ուժգնությունը՝ երկու գիծ:"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi-ի ուժգնությունը՝ երեք գիծ:"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi-ի ազդանշանը ուժեղ է:"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Միացած է ձեր սարքին։"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Բաց ցանց"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Անվտանգ ցանց"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index ca1b6be5b478..e33dd05264c3 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi dua baris"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi tiga baris."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Sinyal Wi-Fi penuh."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Terhubung ke perangkat Anda."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Jaringan terbuka"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Jaringan aman"</string> <string name="process_kernel_label" msgid="950292573930336765">"OS Android"</string> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 1f2dcfb7c790..e1fb248604c2 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi: Tvö strik."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: Þrjú strik."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Fullur Wi-Fi sendistyrkur."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Tengt við tækið þitt."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Opið net"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Öruggt net"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android stýrikerfið"</string> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index e255c85a7d69..b2cfd371fe25 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi: due barre."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: tre barre."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Segnale Wi-Fi completo."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Connessione al dispositivo effettuata."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rete aperta"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rete protetta"</string> <string name="process_kernel_label" msgid="950292573930336765">"Sistema operativo Android"</string> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index edcac10e8f24..9ca74778d978 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"שני פסים של Wi-Fi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"שלושה פסים של Wi-Fi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"אות Wi-Fi מלא."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"מחובר למכשיר שלך."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"רשת פתוחה"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"רשת מאובטחת"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index bf21de291e6a..dcce2b4436aa 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fiはレベル2です。"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fiはレベル3です。"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fiの電波はフルです。"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"デバイスに接続しました。"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"オープンネットワーク"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"保護されたネットワーク"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index 9000de4c990b..eb32e1ce2a8d 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WiFi სიგნალი ორ ზოლზეა."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WiFi სიგნალი სამ ზოლზეა."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WiFi სიგნალი სრულია."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"დაკავშირებულია თქვენს მოწყობილობასთან."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ღია ქსელი"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"დაცული ქსელი"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index 610fed1f6550..73a8efde7a97 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi сигналы — екі жолақ."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi сигналы — үш жолақ."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi сигналы толық."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Құрылғыңызға жалғанды."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Ашық желі"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Қауіпсіз желі"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index b7999c73f33a..1c32e626f1b6 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi ពីរកាំ"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi បីកាំ"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"សេវា Wifi ពេញ"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"បានភ្ជាប់ទៅឧបករណ៍របស់អ្នក។"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"បើកបណ្ដាញ"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"បណ្តាញដែលមានសុវត្ថិភាព"</string> <string name="process_kernel_label" msgid="950292573930336765">"ប្រព័ន្ធប្រតិបត្តិការ Android"</string> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index c788dd5fc8bd..ede347db975f 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"ವೈಫೈ ಎರಡು ಪಟ್ಟಿಗಳು."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"ವೈಫೈ ಮೂರು ಪಟ್ಟಿಗಳು."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"ವೈಫೈ ಸಿಗ್ನಲ್ ಪೂರ್ತಿ ಇದೆ."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ನೆಟ್ವರ್ಕ್ ತೆರೆಯಿರಿ"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"ಸುರಕ್ಷಿತ ನೆಟ್ವರ್ಕ್"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index 2c51d1f9edd1..78bd616dffe2 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi 신호 막대가 두 개입니다."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi 신호 막대가 세 개입니다."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi 신호가 강합니다."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"기기에 연결되었습니다."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"개방형 네트워크"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"보안 네트워크"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index 14814f4ed6e8..a0b91230713d 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi: эки таякча."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi: үч таякча."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi: күчтүү сигнал."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Түзмөгүңүзгө туташты."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Ачык тармак"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Коопсуз тармак"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index 6430a9889e1a..96b2dc1a27cb 100644 --- a/packages/SettingsLib/res/values-lo/strings.xml +++ b/packages/SettingsLib/res/values-lo/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"ສັນຍານ Wi-Fi ສອງຂີດ."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi ສາມຂີດ."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"ສັນຍານ Wi-Fi ເຕັມ"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"ເຊື່ອມຕໍ່ກັບອຸປະກອນຂອງທ່ານແລ້ວ."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ເຄືອຂ່າຍເປີດ"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"ເຄືອຂ່າຍເຂົ້າລະຫັດ"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index 3642a9091545..69630f436704 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Dvi „Wi-Fi“ signalo juostos."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Trys „Wi-Fi“ signalo juostos."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Stiprus „Wi-Fi“ signalas."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Prisijungta prie įrenginio."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Atviras tinklas"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Saugus tinklas"</string> <string name="process_kernel_label" msgid="950292573930336765">"„Android“ OS"</string> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index c3163b8efe1e..4f76ceeb2cca 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi: divas joslas"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: trīs joslas"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Pilna piekļuve Wi-Fi signālam"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Izveidots savienojums ar ierīci."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Atvērts tīkls"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Drošs tīkls"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index 017fed7a5524..1c80c6502fc1 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Две црти на Wi-Fi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Три црти на Wi-Fi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Полн сигнал на Wi-Fi."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Поврзано со уредот."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Отворена мрежа"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Заклучена мрежа"</string> <string name="process_kernel_label" msgid="950292573930336765">"Оперативен систем Android"</string> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index 3ef3f63d32b7..31e3c83fb32f 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"വൈഫൈ സിഗ്നൽ രണ്ട് ബാറുകൾ."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"വൈഫൈ സിഗ്നൽ മൂന്ന് ബാറുകൾ."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"വൈഫൈ മികച്ച സിഗ്നൽ."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"നിങ്ങളുടെ ഉപകരണത്തിലേക്ക് കണക്റ്റ് ചെയ്തു."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ഓപ്പൺ നെറ്റ്വര്ക്ക്"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"സുരക്ഷിത നെറ്റ്വര്ക്ക്"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index ccd1d4179ffb..5a636d9c8260 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi сүлжээний дохио хоёр баганатай байна."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi сүлжээний дохио гурван баганатай байна."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi-н дохио дүүрэн байна."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Таны төхөөрөмжид холбогдсон."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Нээлттэй сүлжээ"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Аюулгүй сүлжээ"</string> <string name="process_kernel_label" msgid="950292573930336765">"Андройд OS"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index a34a9d327969..4d78e571b47d 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"वाय-फाय दोन बार."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"वाय-फाय तीन बार."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"वाय-फाय सिग्नल संपूर्ण आहे."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"तुमच्या डिव्हाइसशी कनेक्ट केले आहे."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"नेटवर्क उघडा"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"सुरक्षित नेटवर्क"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index b7d273409390..2ae69bdff241 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi dua bar."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi tiga bar."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Isyarat Wi-Fi penuh."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Disambungkan kepada peranti anda."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rangkaian terbuka"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rangkaian selamat"</string> <string name="process_kernel_label" msgid="950292573930336765">"OS Android"</string> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index 0e43f6516f25..7d6f2a75ba5a 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi ၂ ဘား"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi ၃ ဘား"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi အပြည့်ရှိ"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"သင့်စက်သို့ ချိတ်ဆက်ထားသည်။"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"အများသုံး ကွန်ရက်"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"လုံခြုံသည့် ကွန်ရက်"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 43824c3ebc1a..9e550fb288e9 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi-signal med to stolper."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi-signal med tre stolper."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi-signalet er ved full styrke."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Koblet til enheten."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Åpent nettverk"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sikkert nettverk"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android-operativsystem"</string> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index e879849f5f29..1f6ad5bb863c 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi दुई पट्टि।"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi तीन बारहरू।"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"पूर्ण Wi-Fi सिंग्नल।"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"तपाईंको डिभाइसमा कनेक्ट गरिएको छ।"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"खुला नेटवर्क"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"सुरक्षित नेटवर्क"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index dedacff6daf3..6a6f184f77d1 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi: twee streepjes."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi: drie streepjes."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifii-signaal is op volledige sterkte."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Verbonden met je apparaat."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Open netwerk"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Beveiligd netwerk"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android-besturingssysteem"</string> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index cbd9ffd50771..980a37413f8b 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"ୱାଇ-ଫାଇର ଦୁଇଟି ବାର୍ ଅଛି।"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"ୱାଇ-ଫାଇର ତିନୋଟି ବାର୍।"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"ୱାଇ-ଫାଇର ସଙ୍କେତ ସର୍ବୋଚ୍ଚ।"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"ଆପଣଙ୍କ ଡିଭାଇସ ସହ କନେକ୍ଟ କରାଯାଇଛି।"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ଖୋଲା ନେଟୱର୍କ"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"ସୁରକ୍ଷିତ ନେଟ୍ୱର୍କ"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index e4814acdfb0c..dd3fa15440e1 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi ਦੋ ਬਾਰ।"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi ਤਿੰਨ ਬਾਰ।"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi ਸਿਗਨਲ ਪੂਰਾ।"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ।"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ਖੁੱਲ੍ਹਾ ਨੈੱਟਵਰਕ"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"ਸੁਰੱਖਿਅਤ ਨੈੱਟਵਰਕ"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index f5dc9cc7e202..f4ebd29b1276 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi: dwa paski."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: trzy paski."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi: pełna moc sygnału."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Połączono z urządzeniem."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Sieć otwarta"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sieć zabezpieczona"</string> <string name="process_kernel_label" msgid="950292573930336765">"System operacyjny Android"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index 4e96bc615c3d..bb6c7d85fe62 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Duas barras de Wi-Fi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Três barras de Wi-Fi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Sinal Wi-Fi cheio."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Conectado ao dispositivo."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rede aberta"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rede segura"</string> <string name="process_kernel_label" msgid="950292573930336765">"Sistema operacional Android"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index 0c4abdbefda2..6bd5c2abccda 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Duas barras de Wi-Fi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Três barras de Wi-Fi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Sinal de Wi-Fi completo."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Com ligação ao dispositivo."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rede aberta"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rede segura"</string> <string name="process_kernel_label" msgid="950292573930336765">"SO Android"</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index 4e96bc615c3d..bb6c7d85fe62 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Duas barras de Wi-Fi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Três barras de Wi-Fi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Sinal Wi-Fi cheio."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Conectado ao dispositivo."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rede aberta"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rede segura"</string> <string name="process_kernel_label" msgid="950292573930336765">"Sistema operacional Android"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 529a6c646979..f4399dc4e829 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Semnal Wi-Fi: două bare."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Semnal Wi-Fi: trei bare."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Semnal Wi-Fi: complet."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Conectată la dispozitiv."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rețea nesecurizată"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Securizează rețeaua"</string> <string name="process_kernel_label" msgid="950292573930336765">"Sistem de operare Android"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 87a81ee73faf..5d45e29ef9b6 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi: два деления"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: три деления"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi: надежный сигнал"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Подключено к точке доступа на вашем устройстве."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Открытая сеть"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Защищенная сеть"</string> <string name="process_kernel_label" msgid="950292573930336765">"ОС Android"</string> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index 9015a428de38..996507d8c2f6 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi තීරු දෙකයි."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WiFi තීරු තුනයි."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi සංඥාව පිරී ඇත."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"ඔබේ උපාංගයට සම්බන්ධයි."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"විවෘත ජාලය"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"ආරක්ෂිත ජාලය"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index 8c6bf4fcb887..a51acd4fb227 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Dve čiarky signálu Wi‑Fi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Tri čiarky signálu Wi‑Fi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Plný signál Wi‑Fi."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Pripojené k vášmu zariadeniu."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Otvorená sieť"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Zabezpečená sieť"</string> <string name="process_kernel_label" msgid="950292573930336765">"OS Android"</string> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index cc19abe8be24..0d7188dcbc50 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Dve črtici signala Wi-Fi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Tri črtice signala Wi-Fi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Poln signal Wi-Fi."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Povezava z napravo je vzpostavljena."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Odprto omrežje"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Varno omrežje"</string> <string name="process_kernel_label" msgid="950292573930336765">"OS Android"</string> diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml index 43a2c4c19fd1..c2bcce79b061 100644 --- a/packages/SettingsLib/res/values-sq/strings.xml +++ b/packages/SettingsLib/res/values-sq/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi ka dy vija."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: tre vija."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi ka sinjal të plotë."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Lidhur me pajisjen tënde"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rrjet i hapur"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rrjet i sigurt"</string> <string name="process_kernel_label" msgid="950292573930336765">"Sistemi operativ Android"</string> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 00a98bca2383..09ff994477e1 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WiFi сигнал има две црте."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WiFi сигнал има три црте."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WiFi сигнал је најјачи."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Повезано је са уређајем."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Отворена мрежа"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Безбедна мрежа"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android ОС"</string> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index 01b462da0165..fdd9d8c17d57 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi: två staplar."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi: tre staplar."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Full signalstyrka för wifi."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Ansluten till enheten."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Öppet nätverk"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Säkert nätverk"</string> <string name="process_kernel_label" msgid="950292573930336765">"Operativsystemet Android"</string> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index 9453e5f84c6c..bd4175289585 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Vipima mtandao viwili vya Wifi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Vipima mtandao vitatu vya Wifi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Nguvu kamili ya mtandao wa Wifi."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Imeunganishwa kwenye kifaa chako."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Mtandao unaotumiwa na mtu yeyote"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Mtandao salama"</string> <string name="process_kernel_label" msgid="950292573930336765">"Mfumo wa Uendeshaji wa Android"</string> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index 836b4da9b8a7..fd379f0a80be 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"வைஃபை சிக்னல்: இரண்டு கோடுகள்."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"வைஃபை சிக்னல்: மூன்று கோடுகள்."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"வைஃபை சிக்னல் முழுமையாக உள்ளது."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"உங்கள் சாதனத்துடன் இணைக்கப்பட்டது."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"கடவுச்சொல் தேவைப்படாத திறந்த நெட்வொர்க்"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"கடவுச்சொல் தேவைப்படும் பாதுகாப்பான நெட்வொர்க்"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index 34b826441dbc..3e9d8be3cc1b 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi సిగ్నల్ రెండు బార్లు ఉంది."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi సిగ్నల్ మూడు బార్లు ఉంది."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi సిగ్నల్ పూర్తిగా ఉంది."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"మీ పరికరానికి కనెక్ట్ చేయబడింది."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ఓపెన్ నెట్వర్క్"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"సురక్షిత నెట్వర్క్"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index da3a5c5d09c6..e67f37172bd7 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"สัญญาณ Wi-Fi 2 ขีด"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"สัญญาณ Wi-Fi 3 ขีด"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"สัญญาณ Wi-Fi เต็ม"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"เชื่อมต่อกับอุปกรณ์แล้ว"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"เครือข่ายแบบเปิด"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"เครือข่ายที่ปลอดภัย"</string> <string name="process_kernel_label" msgid="950292573930336765">"ระบบปฏิบัติการ Android"</string> @@ -598,7 +597,7 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"ข้อมูลโปรไฟล์"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"ก่อนที่คุณจะสามารถสร้างโปรไฟล์ที่ถูกจำกัดได้ คุณจะต้องตั้งค่าล็อกหน้าจอเพื่อปกป้องแอปและข้อมูลส่วนตัวของคุณ"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"ตั้งค่าล็อก"</string> - <string name="user_switch_to_user" msgid="6975428297154968543">"เปลี่ยนเป็น <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="user_switch_to_user" msgid="6975428297154968543">"เปลี่ยนเป็น<xliff:g id="USER_NAME">%s</xliff:g>"</string> <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"กำลังสร้างผู้ใช้ใหม่…"</string> <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"กำลังสร้างผู้ใช้ชั่วคราวใหม่…"</string> <string name="add_user_failed" msgid="4809887794313944872">"สร้างผู้ใช้ใหม่ไม่ได้"</string> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index f6d2256c3e4e..440bbe768c05 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"May dalawang bar ang Wifi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"May tatlong bar ang Wifi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Puno ang signal ng Wifi."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Nakakonekta sa iyong device."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Bukas na network"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Ligtas na network"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index acd3d00e56e6..b38012fbbd8c 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Kablosuz sinyal gücü iki çubuk."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Kablosuz sinyal gücü üç çubuk."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Kablosuz sinyal gücü tam."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Cihazınıza bağlandı."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Açık ağ"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Güvenli ağ"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index dd5898adc3c5..4f0854790e92 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Дві смужки сигналу Wi-Fi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Три смужки сигналу Wi-Fi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Максимальний сигнал Wi-Fi."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Підключено до пристрою."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Відкрита мережа"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Захищена мережа"</string> <string name="process_kernel_label" msgid="950292573930336765">"ОС Android"</string> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index 182bd0496527..ce67d1516273 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi دو بارز۔"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi تین بارز۔"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi سگنل پورا ہے۔"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"آپ کے آلے سے منسلک ہے۔"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"اوپن نیٹ ورک"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"محفوظ نیٹ ورک"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index b831a4b40bb9..77da981b29a9 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi: ikkita ustun"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: uchta ustun"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi: signal to‘liq"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Qurilmaga ulandi."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Ochiq tarmoq"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Xavfsiz tarmoq"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index 3e94593351a2..bf510f6522f3 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Tín hiệu Wi-Fi hai vạch."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Tín hiệu Wi-Fi ba vạch."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Tín hiệu Wi-Fi đủ."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Đã kết nối với thiết bị của bạn."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Mạng mở"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Mạng bảo mật"</string> <string name="process_kernel_label" msgid="950292573930336765">"Hệ điều hành Android"</string> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index 53389c790974..8e3145ace05a 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WLAN 信号强度为两格。"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WLAN 信号强度为三格。"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WLAN 信号满格。"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"已连接到您的设备。"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"开放网络"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"安全网络"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android 操作系统"</string> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index daedba67c378..aa9f21f28b91 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi 訊號兩格。"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi 訊號三格。"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi 訊號滿格。"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"已連接裝置。"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"開放式網絡"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"安全網絡"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android 作業系統"</string> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 94ebd9852e85..3c65a4d7d5ee 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi 訊號強度兩格。"</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi 訊號強度三格。"</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi 訊號強度滿格。"</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"已連上裝置。"</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"開放式網路"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"安全網路"</string> <string name="process_kernel_label" msgid="950292573930336765">"Android 作業系統"</string> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index 92a4b81e80f7..08b04cc4b1bf 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -157,8 +157,7 @@ <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Amabha amabili we-Wifi."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Amabha amathathu we-Wifi."</string> <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Isiginali ye-Wifi igcwele."</string> - <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) --> - <skip /> + <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Ixhume kudivayisi yakho."</string> <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Vula inethiwekhi"</string> <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Inethiwekhi evikelekile"</string> <string name="process_kernel_label" msgid="950292573930336765">"I-Android OS"</string> diff --git a/packages/SettingsLib/tests/integ/Android.bp b/packages/SettingsLib/tests/integ/Android.bp index b03c43cbdee5..4b4caf5a620e 100644 --- a/packages/SettingsLib/tests/integ/Android.bp +++ b/packages/SettingsLib/tests/integ/Android.bp @@ -52,7 +52,7 @@ android_test { "flag-junit", "mockito-target-minus-junit4", "platform-test-annotations", - "truth-prebuilt", + "truth", "SettingsLibDeviceStateRotationLock", "SettingsLibSettingsSpinner", "SettingsLibUsageProgressBarPreference", diff --git a/packages/SettingsLib/tests/robotests/Android.bp b/packages/SettingsLib/tests/robotests/Android.bp index dd9cb9cf7abe..2d875cf7244d 100644 --- a/packages/SettingsLib/tests/robotests/Android.bp +++ b/packages/SettingsLib/tests/robotests/Android.bp @@ -96,6 +96,6 @@ java_library { libs: [ "Robolectric_all-target_upstream", "mockito-robolectric-prebuilt", - "truth-prebuilt", + "truth", ], } diff --git a/packages/SettingsLib/tests/unit/Android.bp b/packages/SettingsLib/tests/unit/Android.bp index 19ab1c69e98c..6d6e2ff8e59b 100644 --- a/packages/SettingsLib/tests/unit/Android.bp +++ b/packages/SettingsLib/tests/unit/Android.bp @@ -31,6 +31,6 @@ android_test { "SettingsLib", "androidx.test.ext.junit", "androidx.test.runner", - "truth-prebuilt", + "truth", ], } diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp index 92ebe09fa441..f4ca260d4d89 100644 --- a/packages/SettingsProvider/Android.bp +++ b/packages/SettingsProvider/Android.bp @@ -64,7 +64,7 @@ android_test { "SettingsLibDeviceStateRotationLock", "SettingsLibDisplayUtils", "platform-test-annotations", - "truth-prebuilt", + "truth", ], libs: [ "android.test.base", diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 91d2d1bb58e5..96f3290d1c76 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -218,6 +218,7 @@ public class SecureSettings { Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED, + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE, Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED, Settings.Secure.NOTIFICATION_BUBBLES, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, @@ -244,6 +245,9 @@ public class SecureSettings { Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED, Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED, Settings.Secure.SEARCH_LONG_PRESS_HOME_ENABLED, - Settings.Secure.HUB_MODE_TUTORIAL_STATE + Settings.Secure.HUB_MODE_TUTORIAL_STATE, + Settings.Secure.STYLUS_BUTTONS_ENABLED, + Settings.Secure.STYLUS_HANDWRITING_ENABLED, + Settings.Secure.DEFAULT_NOTE_TASK_PROFILE }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java index 248c60cb4fe9..f5d9475fb049 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java @@ -101,5 +101,7 @@ public class SystemSettings { Settings.System.CAMERA_FLASH_NOTIFICATION, Settings.System.SCREEN_FLASH_NOTIFICATION, Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, + Settings.System.PEAK_REFRESH_RATE, + Settings.System.MIN_REFRESH_RATE, }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index bec144766438..f48600db8735 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -308,6 +308,10 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE, + new InclusiveIntegerRangeValidator( + Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE_NONE, + Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE_ALL)); VALIDATORS.put( Secure.ACCESSIBILITY_BUTTON_TARGETS, ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR); @@ -390,5 +394,9 @@ public class SecureSettingsValidators { BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.DND_CONFIGS_MIGRATED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.HUB_MODE_TUTORIAL_STATE, NON_NEGATIVE_INTEGER_VALIDATOR); + VALIDATORS.put(Secure.STYLUS_BUTTONS_ENABLED, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.STYLUS_HANDWRITING_ENABLED, + new DiscreteValueValidator(new String[] {"-1", "0", "1"})); + VALIDATORS.put(Secure.DEFAULT_NOTE_TASK_PROFILE, NON_NEGATIVE_INTEGER_VALIDATOR); } } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java index 29f27f74bca4..410269f240e0 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java @@ -21,6 +21,7 @@ import static android.provider.settings.validators.SettingsValidators.ANY_STRING import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_FLOAT_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.URI_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.VIBRATION_INTENSITY_VALIDATOR; @@ -236,5 +237,7 @@ public class SystemSettingsValidators { VALIDATORS.put(System.CAMERA_FLASH_NOTIFICATION, BOOLEAN_VALIDATOR); VALIDATORS.put(System.SCREEN_FLASH_NOTIFICATION, BOOLEAN_VALIDATOR); VALIDATORS.put(System.SCREEN_FLASH_NOTIFICATION_COLOR, ANY_INTEGER_VALIDATOR); + VALIDATORS.put(System.PEAK_REFRESH_RATE, NON_NEGATIVE_FLOAT_VALIDATOR); + VALIDATORS.put(System.MIN_REFRESH_RATE, NON_NEGATIVE_FLOAT_VALIDATOR); } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 3c8d4bca2394..f06b31c4e965 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1850,6 +1850,10 @@ class SettingsProtoDumpUtil { SecureSettingsProto.Accessibility .ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED); dumpSetting(s, p, + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE, + SecureSettingsProto.Accessibility + .ACCESSIBILITY_MAGNIFICATION_GESTURE); + dumpSetting(s, p, Settings.Secure.HEARING_AID_RINGTONE_ROUTING, SecureSettingsProto.Accessibility.HEARING_AID_RINGTONE_ROUTING); 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 34d3d446530b..46cd725ad582 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -121,6 +121,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.accessibility.util.AccessibilityUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; +import com.android.internal.display.RefreshRateSettingsUtils; import com.android.internal.os.BackgroundThread; import com.android.internal.util.FrameworkStatsLog; import com.android.providers.settings.SettingsState.Setting; @@ -3878,7 +3879,7 @@ public class SettingsProvider extends ContentProvider { } private final class UpgradeController { - private static final int SETTINGS_VERSION = 222; + private static final int SETTINGS_VERSION = 223; private final int mUserId; @@ -5935,10 +5936,6 @@ public class SettingsProvider extends ContentProvider { if (currentVersion == 218) { // Version 219: Removed - // TODO(b/211737588): Back up the Smooth Display setting - // Future upgrades to the `peak_refresh_rate` and `min_refresh_rate` settings - // should account for the database in a non-upgraded and upgraded (change id: - // Ib2cb2dd100f06f5452083b7606109a486e795a0e) state. currentVersion = 219; } @@ -6004,6 +6001,56 @@ public class SettingsProvider extends ContentProvider { currentVersion = 222; } + // Version 222: Set peak refresh rate and min refresh rate to infinity if it's + // meant to be the highest possible refresh rate. This is needed so that we can + // back up and restore those settings on other devices. Other devices might have + // different highest possible refresh rates. + if (currentVersion == 222) { + final SettingsState systemSettings = getSystemSettingsLocked(userId); + final Setting peakRefreshRateSetting = + systemSettings.getSettingLocked(Settings.System.PEAK_REFRESH_RATE); + final Setting minRefreshRateSetting = + systemSettings.getSettingLocked(Settings.System.MIN_REFRESH_RATE); + float highestRefreshRate = RefreshRateSettingsUtils + .findHighestRefreshRateForDefaultDisplay(getContext()); + + if (!peakRefreshRateSetting.isNull()) { + try { + float peakRefreshRate = + Float.parseFloat(peakRefreshRateSetting.getValue()); + if (Math.round(peakRefreshRate) == Math.round(highestRefreshRate)) { + systemSettings.insertSettingLocked( + Settings.System.PEAK_REFRESH_RATE, + String.valueOf(Float.POSITIVE_INFINITY), + /* tag= */ null, + /* makeDefault= */ false, + SettingsState.SYSTEM_PACKAGE_NAME); + } + } catch (NumberFormatException e) { + // Do nothing. Leave the value as is. + } + } + + if (!minRefreshRateSetting.isNull()) { + try { + float minRefreshRate = + Float.parseFloat(minRefreshRateSetting.getValue()); + if (Math.round(minRefreshRate) == Math.round(highestRefreshRate)) { + systemSettings.insertSettingLocked( + Settings.System.MIN_REFRESH_RATE, + String.valueOf(Float.POSITIVE_INFINITY), + /* tag= */ null, + /* makeDefault= */ false, + SettingsState.SYSTEM_PACKAGE_NAME); + } + } catch (NumberFormatException e) { + // Do nothing. Leave the value as is. + } + } + + currentVersion = 223; + } + // vXXX: Add new settings above this point. if (currentVersion != newVersion) { diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 9ddc976af7e2..7bca944033d9 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -98,8 +98,6 @@ public class SettingsBackupTest { Settings.System.VOLUME_VOICE, // deprecated since API 2? Settings.System.WHEN_TO_MAKE_WIFI_CALLS, // bug? Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, // used for debugging only - Settings.System.MIN_REFRESH_RATE, // depends on hardware capabilities - Settings.System.PEAK_REFRESH_RATE, // depends on hardware capabilities Settings.System.SCREEN_BRIGHTNESS_FLOAT, Settings.System.SCREEN_BRIGHTNESS_FOR_ALS, Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE, @@ -735,7 +733,6 @@ public class SettingsBackupTest { Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, Settings.Secure.CONTENT_CAPTURE_ENABLED, Settings.Secure.DEFAULT_INPUT_METHOD, - Settings.Secure.DEFAULT_NOTE_TASK_PROFILE, Settings.Secure.DEVICE_PAIRED, Settings.Secure.DIALER_DEFAULT_APPLICATION, Settings.Secure.DISABLED_PRINT_SERVICES, @@ -805,8 +802,6 @@ public class SettingsBackupTest { Settings.Secure.SLEEP_TIMEOUT, Settings.Secure.SMS_DEFAULT_APPLICATION, Settings.Secure.SPELL_CHECKER_ENABLED, // Intentionally removed in Q - Settings.Secure.STYLUS_BUTTONS_ENABLED, - Settings.Secure.STYLUS_HANDWRITING_ENABLED, Settings.Secure.TRUST_AGENTS_INITIALIZED, Settings.Secure.KNOWN_TRUST_AGENTS_INITIALIZED, Settings.Secure.TV_APP_USES_NON_SYSTEM_INPUTS, diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 3c5785275919..e40fcb2a633b 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -466,7 +466,7 @@ android_library { "hamcrest-library", "androidx.test.rules", "testables", - "truth-prebuilt", + "truth", "monet", "libmonet", "dagger2", @@ -583,7 +583,7 @@ android_robolectric_test { "android.test.runner", "android.test.base", "android.test.mock", - "truth-prebuilt", + "truth", ], upstream: true, diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp b/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp index 538ecb3d438d..3fc351c32ec1 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp +++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp @@ -32,7 +32,7 @@ android_test { "androidx.test.ext.junit", "compatibility-device-util-axt", "platform-test-annotations", - "truth-prebuilt", + "truth", ], srcs: [ "src/**/*.java", diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt index 0f2e4bace46d..4aac27932924 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt @@ -39,6 +39,7 @@ import android.view.ViewGroup import android.view.WindowManager import android.view.animation.Interpolator import android.view.animation.PathInterpolator +import androidx.annotation.AnyThread import androidx.annotation.BinderThread import androidx.annotation.UiThread import com.android.app.animation.Interpolators @@ -149,6 +150,10 @@ class ActivityLaunchAnimator( override fun onLaunchAnimationProgress(linearProgress: Float) { listeners.forEach { it.onLaunchAnimationProgress(linearProgress) } } + + override fun onLaunchAnimationCancelled() { + listeners.forEach { it.onLaunchAnimationCancelled() } + } } /** @@ -191,6 +196,7 @@ class ActivityLaunchAnimator( "ActivityLaunchAnimator.callback must be set before using this animator" ) val runner = createRunner(controller) + val runnerDelegate = runner.delegate!! val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen // Pass the RemoteAnimationAdapter to the intent starter only if we are not hiding the @@ -241,12 +247,15 @@ class ActivityLaunchAnimator( // If we expect an animation, post a timeout to cancel it in case the remote animation is // never started. if (willAnimate) { - runner.delegate.postTimeout() + runnerDelegate.postTimeout() // Hide the keyguard using the launch animation instead of the default unlock animation. if (hideKeyguardWithAnimation) { callback.hideKeyguardWithAnimation(runner) } + } else { + // We need to make sure delegate references are dropped to avoid memory leaks. + runner.dispose() } } @@ -344,6 +353,13 @@ class ActivityLaunchAnimator( */ fun onLaunchAnimationEnd() {} + /** + * The animation was cancelled. Note that [onLaunchAnimationEnd] will still be called after + * this if the animation was already started, i.e. if [onLaunchAnimationStart] was called + * before the cancellation. + */ + fun onLaunchAnimationCancelled() {} + /** Called when an activity launch animation made progress. */ fun onLaunchAnimationProgress(linearProgress: Float) {} } @@ -426,6 +442,39 @@ class ActivityLaunchAnimator( fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean? = null) {} } + /** + * Invokes [onAnimationComplete] when animation is either cancelled or completed. Delegates all + * events to the passed [delegate]. + */ + @VisibleForTesting + inner class DelegatingAnimationCompletionListener( + private val delegate: Listener?, + private val onAnimationComplete: () -> Unit + ) : Listener { + var cancelled = false + + override fun onLaunchAnimationStart() { + delegate?.onLaunchAnimationStart() + } + + override fun onLaunchAnimationProgress(linearProgress: Float) { + delegate?.onLaunchAnimationProgress(linearProgress) + } + + override fun onLaunchAnimationEnd() { + delegate?.onLaunchAnimationEnd() + if (!cancelled) { + onAnimationComplete.invoke() + } + } + + override fun onLaunchAnimationCancelled() { + cancelled = true + delegate?.onLaunchAnimationCancelled() + onAnimationComplete.invoke() + } + } + @VisibleForTesting inner class Runner( controller: Controller, @@ -436,11 +485,21 @@ class ActivityLaunchAnimator( listener: Listener? = null ) : IRemoteAnimationRunner.Stub() { private val context = controller.launchContainer.context - internal val delegate: AnimationDelegate + + // 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 + // transitively cause leaks when we're done with animation. + @VisibleForTesting var delegate: AnimationDelegate? init { delegate = - AnimationDelegate(controller, callback, listener, launchAnimator, disableWmTimeout) + AnimationDelegate( + controller, + callback, + DelegatingAnimationCompletionListener(listener, this::dispose), + launchAnimator, + disableWmTimeout + ) } @BinderThread @@ -451,14 +510,33 @@ class ActivityLaunchAnimator( nonApps: Array<out RemoteAnimationTarget>?, finishedCallback: IRemoteAnimationFinishedCallback? ) { + val delegate = delegate context.mainExecutor.execute { - delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback) + if (delegate == null) { + Log.i(TAG, "onAnimationStart called after completion") + // Animation started too late and timed out already. We need to still + // signal back that we're done with it. + finishedCallback?.onAnimationFinished() + } else { + delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback) + } } } @BinderThread override fun onAnimationCancelled() { - context.mainExecutor.execute { delegate.onAnimationCancelled() } + val delegate = delegate + context.mainExecutor.execute { + delegate ?: Log.wtf(TAG, "onAnimationCancelled called after completion") + delegate?.onAnimationCancelled() + } + } + + @AnyThread + fun dispose() { + // Drop references to animation controller once we're done with the animation + // to avoid leaking. + context.mainExecutor.execute { delegate = null } } } @@ -584,6 +662,7 @@ class ActivityLaunchAnimator( ) } controller.onLaunchAnimationCancelled() + listener?.onLaunchAnimationCancelled() return } @@ -821,6 +900,7 @@ class ActivityLaunchAnimator( Log.d(TAG, "Calling controller.onLaunchAnimationCancelled() [animation timed out]") } controller.onLaunchAnimationCancelled() + listener?.onLaunchAnimationCancelled() } @UiThread @@ -842,6 +922,7 @@ class ActivityLaunchAnimator( ) } controller.onLaunchAnimationCancelled() + listener?.onLaunchAnimationCancelled() } private fun IRemoteAnimationFinishedCallback.invoke() { diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt index 39173d98538f..58c7bdbf3d71 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt @@ -130,10 +130,23 @@ interface SceneScope { sealed interface UserAction /** The user navigated back, either using a gesture or by triggering a KEYCODE_BACK event. */ -object Back : UserAction +data object Back : UserAction /** The user swiped on the container. */ -enum class Swipe : UserAction { +data class Swipe( + val direction: SwipeDirection, + val pointerCount: Int = 1, + val fromEdge: Edge? = null, +) : UserAction { + companion object { + val Left = Swipe(SwipeDirection.Left) + val Up = Swipe(SwipeDirection.Up) + val Right = Swipe(SwipeDirection.Right) + val Down = Swipe(SwipeDirection.Down) + } +} + +enum class SwipeDirection { Up, Down, Left, diff --git a/packages/SystemUI/compose/core/tests/Android.bp b/packages/SystemUI/compose/core/tests/Android.bp index 52c63854f62f..8e9c5864ce70 100644 --- a/packages/SystemUI/compose/core/tests/Android.bp +++ b/packages/SystemUI/compose/core/tests/Android.bp @@ -43,7 +43,7 @@ android_test { "androidx.compose.ui_ui-test-junit4", "androidx.compose.ui_ui-test-manifest", - "truth-prebuilt", + "truth", ], kotlincflags: ["-Xjvm-default=all"], diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt index c3a3752db374..ee310ab41373 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt @@ -36,13 +36,14 @@ import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.viewinterop.AndroidView import androidx.core.view.isVisible import com.android.compose.animation.scene.SceneScope -import com.android.systemui.res.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.qualifiers.KeyguardRootView import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel +import com.android.systemui.res.R import com.android.systemui.scene.shared.model.Direction +import com.android.systemui.scene.shared.model.Edge import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.UserAction @@ -99,7 +100,9 @@ constructor( return buildMap { up?.let { this[UserAction.Swipe(Direction.UP)] = SceneModel(up) } left?.let { this[UserAction.Swipe(Direction.LEFT)] = SceneModel(left) } - this[UserAction.Swipe(Direction.DOWN)] = SceneModel(SceneKey.Shade) + this[UserAction.Swipe(fromEdge = Edge.TOP, direction = Direction.DOWN)] = + SceneModel(SceneKey.QuickSettings) + this[UserAction.Swipe(direction = Direction.DOWN)] = SceneModel(SceneKey.Shade) } } } 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 2ee461fca042..f35ea8373db7 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 @@ -22,6 +22,7 @@ import androidx.compose.ui.Modifier import com.android.compose.animation.scene.SceneScope import com.android.systemui.dagger.SysUISingleton import com.android.systemui.scene.shared.model.Direction +import com.android.systemui.scene.shared.model.Edge import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.UserAction @@ -41,7 +42,12 @@ class GoneScene @Inject constructor() : ComposableScene { override val destinationScenes: StateFlow<Map<UserAction, SceneModel>> = MutableStateFlow<Map<UserAction, SceneModel>>( mapOf( - UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.Shade), + UserAction.Swipe( + pointerCount = 2, + fromEdge = Edge.TOP, + direction = Direction.DOWN, + ) to SceneModel(SceneKey.QuickSettings), + UserAction.Swipe(direction = Direction.DOWN) to SceneModel(SceneKey.Shade), ) ) .asStateFlow() 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 6359ce60ae70..0da562bcb3bb 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 @@ -35,15 +35,18 @@ import androidx.compose.ui.input.pointer.PointerEventPass import androidx.compose.ui.input.pointer.motionEventSpy import androidx.compose.ui.input.pointer.pointerInput import com.android.compose.animation.scene.Back +import com.android.compose.animation.scene.Edge as SceneTransitionEdge import com.android.compose.animation.scene.ObservableTransitionState as SceneTransitionObservableTransitionState import com.android.compose.animation.scene.SceneKey as SceneTransitionSceneKey import com.android.compose.animation.scene.SceneTransitionLayout import com.android.compose.animation.scene.SceneTransitionLayoutState import com.android.compose.animation.scene.Swipe +import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.UserAction as SceneTransitionUserAction import com.android.compose.animation.scene.observableTransitionState import com.android.systemui.ribbon.ui.composable.BottomRightCornerRibbon import com.android.systemui.scene.shared.model.Direction +import com.android.systemui.scene.shared.model.Edge import com.android.systemui.scene.shared.model.ObservableTransitionState import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel @@ -181,12 +184,24 @@ private fun SceneTransitionSceneKey.toModel(): SceneModel { private fun UserAction.toTransitionUserAction(): SceneTransitionUserAction { return when (this) { is UserAction.Swipe -> - when (this.direction) { - Direction.LEFT -> Swipe.Left - Direction.UP -> Swipe.Up - Direction.RIGHT -> Swipe.Right - Direction.DOWN -> Swipe.Down - } + Swipe( + pointerCount = pointerCount, + fromEdge = + when (this.fromEdge) { + null -> null + Edge.LEFT -> SceneTransitionEdge.Left + Edge.TOP -> SceneTransitionEdge.Top + Edge.RIGHT -> SceneTransitionEdge.Right + Edge.BOTTOM -> SceneTransitionEdge.Bottom + }, + direction = + when (this.direction) { + Direction.LEFT -> SwipeDirection.Left + Direction.UP -> SwipeDirection.Up + Direction.RIGHT -> SwipeDirection.Right + Direction.DOWN -> SwipeDirection.Down + } + ) is UserAction.Back -> Back } } diff --git a/packages/SystemUI/customization/res/values-af/strings.xml b/packages/SystemUI/customization/res/values-af/strings.xml new file mode 100644 index 000000000000..4c2c6275e6d8 --- /dev/null +++ b/packages/SystemUI/customization/res/values-af/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Verstek vir digitaal"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-am/strings.xml b/packages/SystemUI/customization/res/values-am/strings.xml new file mode 100644 index 000000000000..847d7a541c95 --- /dev/null +++ b/packages/SystemUI/customization/res/values-am/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ዲጂታል ነባሪ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ar/strings.xml b/packages/SystemUI/customization/res/values-ar/strings.xml new file mode 100644 index 000000000000..57d1612b337d --- /dev/null +++ b/packages/SystemUI/customization/res/values-ar/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"رقمية تلقائية"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-as/strings.xml b/packages/SystemUI/customization/res/values-as/strings.xml new file mode 100644 index 000000000000..2f3b64b9ceb6 --- /dev/null +++ b/packages/SystemUI/customization/res/values-as/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ডিজিটেল ডিফ’ল্ট"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-az/strings.xml b/packages/SystemUI/customization/res/values-az/strings.xml new file mode 100644 index 000000000000..eb52f95a4525 --- /dev/null +++ b/packages/SystemUI/customization/res/values-az/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Rəqəmsal defolt"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/customization/res/values-b+sr+Latn/strings.xml new file mode 100644 index 000000000000..90e6678bdcd6 --- /dev/null +++ b/packages/SystemUI/customization/res/values-b+sr+Latn/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digitalni podrazumevani"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-be/strings.xml b/packages/SystemUI/customization/res/values-be/strings.xml new file mode 100644 index 000000000000..f327da2a40a4 --- /dev/null +++ b/packages/SystemUI/customization/res/values-be/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"электронны, стандартны шрыфт"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-bg/strings.xml b/packages/SystemUI/customization/res/values-bg/strings.xml new file mode 100644 index 000000000000..6e3754a62a29 --- /dev/null +++ b/packages/SystemUI/customization/res/values-bg/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Стандартно дигитално"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-bn/strings.xml b/packages/SystemUI/customization/res/values-bn/strings.xml new file mode 100644 index 000000000000..adf1256b6c82 --- /dev/null +++ b/packages/SystemUI/customization/res/values-bn/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ডিজিটাল ডিফল্ট"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-bs/strings.xml b/packages/SystemUI/customization/res/values-bs/strings.xml new file mode 100644 index 000000000000..8de04ab06503 --- /dev/null +++ b/packages/SystemUI/customization/res/values-bs/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digitalno zadano"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ca/strings.xml b/packages/SystemUI/customization/res/values-ca/strings.xml new file mode 100644 index 000000000000..967bb3f6d2f5 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ca/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital predeterminat"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-cs/strings.xml b/packages/SystemUI/customization/res/values-cs/strings.xml new file mode 100644 index 000000000000..45da4d759ad4 --- /dev/null +++ b/packages/SystemUI/customization/res/values-cs/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digitální výchozí"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-da/strings.xml b/packages/SystemUI/customization/res/values-da/strings.xml new file mode 100644 index 000000000000..3ffaa8b167c8 --- /dev/null +++ b/packages/SystemUI/customization/res/values-da/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Standard (digital)"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-de/strings.xml b/packages/SystemUI/customization/res/values-de/strings.xml new file mode 100644 index 000000000000..64f95e05b245 --- /dev/null +++ b/packages/SystemUI/customization/res/values-de/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital (Standard)"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-el/strings.xml b/packages/SystemUI/customization/res/values-el/strings.xml new file mode 100644 index 000000000000..57134b566d08 --- /dev/null +++ b/packages/SystemUI/customization/res/values-el/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Ψηφιακή προεπιλογή"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-en-rAU/strings.xml b/packages/SystemUI/customization/res/values-en-rAU/strings.xml new file mode 100644 index 000000000000..a6110d5d5b09 --- /dev/null +++ b/packages/SystemUI/customization/res/values-en-rAU/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-en-rCA/strings.xml b/packages/SystemUI/customization/res/values-en-rCA/strings.xml new file mode 100644 index 000000000000..79919c07d189 --- /dev/null +++ b/packages/SystemUI/customization/res/values-en-rCA/strings.xml @@ -0,0 +1,23 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for clock_default_description (5309401440896597541) --> + <skip /> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-en-rGB/strings.xml b/packages/SystemUI/customization/res/values-en-rGB/strings.xml new file mode 100644 index 000000000000..a6110d5d5b09 --- /dev/null +++ b/packages/SystemUI/customization/res/values-en-rGB/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-en-rIN/strings.xml b/packages/SystemUI/customization/res/values-en-rIN/strings.xml new file mode 100644 index 000000000000..a6110d5d5b09 --- /dev/null +++ b/packages/SystemUI/customization/res/values-en-rIN/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-en-rXC/strings.xml b/packages/SystemUI/customization/res/values-en-rXC/strings.xml new file mode 100644 index 000000000000..7c540dab2cfe --- /dev/null +++ b/packages/SystemUI/customization/res/values-en-rXC/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-es-rUS/strings.xml b/packages/SystemUI/customization/res/values-es-rUS/strings.xml new file mode 100644 index 000000000000..59be786849e6 --- /dev/null +++ b/packages/SystemUI/customization/res/values-es-rUS/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Configuración predeterminada digital"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-es/strings.xml b/packages/SystemUI/customization/res/values-es/strings.xml new file mode 100644 index 000000000000..03ef0e5a8cea --- /dev/null +++ b/packages/SystemUI/customization/res/values-es/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital predeterminada"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-et/strings.xml b/packages/SystemUI/customization/res/values-et/strings.xml new file mode 100644 index 000000000000..fec793e99619 --- /dev/null +++ b/packages/SystemUI/customization/res/values-et/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digitaalne vaikimisi"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-eu/strings.xml b/packages/SystemUI/customization/res/values-eu/strings.xml new file mode 100644 index 000000000000..a70c8085ccf0 --- /dev/null +++ b/packages/SystemUI/customization/res/values-eu/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital lehenetsia"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-fa/strings.xml b/packages/SystemUI/customization/res/values-fa/strings.xml new file mode 100644 index 000000000000..6426d5112528 --- /dev/null +++ b/packages/SystemUI/customization/res/values-fa/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"دیجیتال پیشفرض"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-fi/strings.xml b/packages/SystemUI/customization/res/values-fi/strings.xml new file mode 100644 index 000000000000..9b19373a3765 --- /dev/null +++ b/packages/SystemUI/customization/res/values-fi/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digitaalinen (oletus)"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-fr-rCA/strings.xml b/packages/SystemUI/customization/res/values-fr-rCA/strings.xml new file mode 100644 index 000000000000..bbd1208b1922 --- /dev/null +++ b/packages/SystemUI/customization/res/values-fr-rCA/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Numérique, par défaut"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-fr/strings.xml b/packages/SystemUI/customization/res/values-fr/strings.xml new file mode 100644 index 000000000000..5579a427fe71 --- /dev/null +++ b/packages/SystemUI/customization/res/values-fr/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Numérique par défaut"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-gl/strings.xml b/packages/SystemUI/customization/res/values-gl/strings.xml new file mode 100644 index 000000000000..2da93c6f1e34 --- /dev/null +++ b/packages/SystemUI/customization/res/values-gl/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Predeterminada dixital"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-gu/strings.xml b/packages/SystemUI/customization/res/values-gu/strings.xml new file mode 100644 index 000000000000..c578a2e2d322 --- /dev/null +++ b/packages/SystemUI/customization/res/values-gu/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ડિજિટલ ડિફૉલ્ટ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-hi/strings.xml b/packages/SystemUI/customization/res/values-hi/strings.xml new file mode 100644 index 000000000000..6080f802af04 --- /dev/null +++ b/packages/SystemUI/customization/res/values-hi/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"डिजिटल डिफ़ॉल्ट"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-hr/strings.xml b/packages/SystemUI/customization/res/values-hr/strings.xml new file mode 100644 index 000000000000..0a1440fb683b --- /dev/null +++ b/packages/SystemUI/customization/res/values-hr/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digitalni zadani"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-hu/strings.xml b/packages/SystemUI/customization/res/values-hu/strings.xml new file mode 100644 index 000000000000..32618a869a1f --- /dev/null +++ b/packages/SystemUI/customization/res/values-hu/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digitális, alapértelmezett"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-hy/strings.xml b/packages/SystemUI/customization/res/values-hy/strings.xml new file mode 100644 index 000000000000..d45afbf256ab --- /dev/null +++ b/packages/SystemUI/customization/res/values-hy/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Թվային, կանխադրված"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-in/strings.xml b/packages/SystemUI/customization/res/values-in/strings.xml new file mode 100644 index 000000000000..a6110d5d5b09 --- /dev/null +++ b/packages/SystemUI/customization/res/values-in/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-is/strings.xml b/packages/SystemUI/customization/res/values-is/strings.xml new file mode 100644 index 000000000000..5a370d614f0f --- /dev/null +++ b/packages/SystemUI/customization/res/values-is/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Stafræn, sjálfgefið"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-it/strings.xml b/packages/SystemUI/customization/res/values-it/strings.xml new file mode 100644 index 000000000000..2a5087d30669 --- /dev/null +++ b/packages/SystemUI/customization/res/values-it/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digitale - predefinito"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-iw/strings.xml b/packages/SystemUI/customization/res/values-iw/strings.xml new file mode 100644 index 000000000000..ddd28f21ad99 --- /dev/null +++ b/packages/SystemUI/customization/res/values-iw/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"דיגיטלי ברירת מחדל"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ja/strings.xml b/packages/SystemUI/customization/res/values-ja/strings.xml new file mode 100644 index 000000000000..744604a17efa --- /dev/null +++ b/packages/SystemUI/customization/res/values-ja/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"デジタル デフォルト"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ka/strings.xml b/packages/SystemUI/customization/res/values-ka/strings.xml new file mode 100644 index 000000000000..88ba1dfc0976 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ka/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ციფრული ნაგულისხმევი"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-kk/strings.xml b/packages/SystemUI/customization/res/values-kk/strings.xml new file mode 100644 index 000000000000..9ee6522c49ce --- /dev/null +++ b/packages/SystemUI/customization/res/values-kk/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Цифрлық әдепкі"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-km/strings.xml b/packages/SystemUI/customization/res/values-km/strings.xml new file mode 100644 index 000000000000..bbc438a69bcd --- /dev/null +++ b/packages/SystemUI/customization/res/values-km/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"លំនាំដើមឌីជីថល"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-kn/strings.xml b/packages/SystemUI/customization/res/values-kn/strings.xml new file mode 100644 index 000000000000..e67319d4021b --- /dev/null +++ b/packages/SystemUI/customization/res/values-kn/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ಡಿಜಿಟಲ್ ಡೀಫಾಲ್ಟ್"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ko/strings.xml b/packages/SystemUI/customization/res/values-ko/strings.xml new file mode 100644 index 000000000000..fa9103b01e66 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ko/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"디지털 기본"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ky/strings.xml b/packages/SystemUI/customization/res/values-ky/strings.xml new file mode 100644 index 000000000000..76cc5e211a40 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ky/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Демейки санариптик"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-lo/strings.xml b/packages/SystemUI/customization/res/values-lo/strings.xml new file mode 100644 index 000000000000..28f50008bd73 --- /dev/null +++ b/packages/SystemUI/customization/res/values-lo/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ດິຈິຕອນຕາມຄ່າເລີ່ມຕົ້ນ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-lt/strings.xml b/packages/SystemUI/customization/res/values-lt/strings.xml new file mode 100644 index 000000000000..2fe731547762 --- /dev/null +++ b/packages/SystemUI/customization/res/values-lt/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Skaitmeninis numatytasis"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-lv/strings.xml b/packages/SystemUI/customization/res/values-lv/strings.xml new file mode 100644 index 000000000000..e0b904a8a1c9 --- /dev/null +++ b/packages/SystemUI/customization/res/values-lv/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digitālais pulkstenis — noklusējums"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-mk/strings.xml b/packages/SystemUI/customization/res/values-mk/strings.xml new file mode 100644 index 000000000000..9b95a6e32b31 --- /dev/null +++ b/packages/SystemUI/customization/res/values-mk/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Дигитален стандарден приказ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ml/strings.xml b/packages/SystemUI/customization/res/values-ml/strings.xml new file mode 100644 index 000000000000..7f6be8a59904 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ml/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ഡിജിറ്റൽ ഡിഫോൾട്ട്"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-mn/strings.xml b/packages/SystemUI/customization/res/values-mn/strings.xml new file mode 100644 index 000000000000..38369b6f527d --- /dev/null +++ b/packages/SystemUI/customization/res/values-mn/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Дижитал өгөгдмөл"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-mr/strings.xml b/packages/SystemUI/customization/res/values-mr/strings.xml new file mode 100644 index 000000000000..821ff100ab13 --- /dev/null +++ b/packages/SystemUI/customization/res/values-mr/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"डिजिटल डीफॉल्टसह क्लॉक फेस"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ms/strings.xml b/packages/SystemUI/customization/res/values-ms/strings.xml new file mode 100644 index 000000000000..2f61b47a2324 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ms/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital lalai"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-my/strings.xml b/packages/SystemUI/customization/res/values-my/strings.xml new file mode 100644 index 000000000000..3d137ebc3abb --- /dev/null +++ b/packages/SystemUI/customization/res/values-my/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ဒစ်ဂျစ်တယ်နာရီ မူရင်း"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-nb/strings.xml b/packages/SystemUI/customization/res/values-nb/strings.xml new file mode 100644 index 000000000000..6eb4373c448c --- /dev/null +++ b/packages/SystemUI/customization/res/values-nb/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital – standard"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ne/strings.xml b/packages/SystemUI/customization/res/values-ne/strings.xml new file mode 100644 index 000000000000..c5b087744a18 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ne/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"डिजिटल डिफल्ट"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-nl/strings.xml b/packages/SystemUI/customization/res/values-nl/strings.xml new file mode 100644 index 000000000000..4f46ab8b2ba5 --- /dev/null +++ b/packages/SystemUI/customization/res/values-nl/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Standaard digitaal"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-or/strings.xml b/packages/SystemUI/customization/res/values-or/strings.xml new file mode 100644 index 000000000000..a74017f6b689 --- /dev/null +++ b/packages/SystemUI/customization/res/values-or/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ଡିଜିଟାଲ ଡିଫଲ୍ଟ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-pa/strings.xml b/packages/SystemUI/customization/res/values-pa/strings.xml new file mode 100644 index 000000000000..a77661a8f56b --- /dev/null +++ b/packages/SystemUI/customization/res/values-pa/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ਡਿਜੀਟਲ ਡਿਫਾਲਟ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-pl/strings.xml b/packages/SystemUI/customization/res/values-pl/strings.xml new file mode 100644 index 000000000000..6f5b6f280dd1 --- /dev/null +++ b/packages/SystemUI/customization/res/values-pl/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Cyfrowa domyślna"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-pt-rPT/strings.xml b/packages/SystemUI/customization/res/values-pt-rPT/strings.xml new file mode 100644 index 000000000000..c6c3cc046965 --- /dev/null +++ b/packages/SystemUI/customization/res/values-pt-rPT/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Predefinição digital"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-pt/strings.xml b/packages/SystemUI/customization/res/values-pt/strings.xml new file mode 100644 index 000000000000..bbe435543211 --- /dev/null +++ b/packages/SystemUI/customization/res/values-pt/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital padrão"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ro/strings.xml b/packages/SystemUI/customization/res/values-ro/strings.xml new file mode 100644 index 000000000000..ef163e96f79f --- /dev/null +++ b/packages/SystemUI/customization/res/values-ro/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Implicit digital"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ru/strings.xml b/packages/SystemUI/customization/res/values-ru/strings.xml new file mode 100644 index 000000000000..5ee928e0fa37 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ru/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Цифровые часы, стандартный"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-si/strings.xml b/packages/SystemUI/customization/res/values-si/strings.xml new file mode 100644 index 000000000000..caf9610e921e --- /dev/null +++ b/packages/SystemUI/customization/res/values-si/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ඩිජිටල් පෙරනිමිය"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sk/strings.xml b/packages/SystemUI/customization/res/values-sk/strings.xml new file mode 100644 index 000000000000..1843f971d251 --- /dev/null +++ b/packages/SystemUI/customization/res/values-sk/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digitálne predvolené"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sl/strings.xml b/packages/SystemUI/customization/res/values-sl/strings.xml new file mode 100644 index 000000000000..12df66f571d3 --- /dev/null +++ b/packages/SystemUI/customization/res/values-sl/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digitalna (privzeta)"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sq/strings.xml b/packages/SystemUI/customization/res/values-sq/strings.xml new file mode 100644 index 000000000000..1fc9f252175f --- /dev/null +++ b/packages/SystemUI/customization/res/values-sq/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Dixhitale e parazgjedhur"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sr/strings.xml b/packages/SystemUI/customization/res/values-sr/strings.xml new file mode 100644 index 000000000000..6b127c9f79e5 --- /dev/null +++ b/packages/SystemUI/customization/res/values-sr/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Дигитални подразумевани"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sv/strings.xml b/packages/SystemUI/customization/res/values-sv/strings.xml new file mode 100644 index 000000000000..84ad25c96655 --- /dev/null +++ b/packages/SystemUI/customization/res/values-sv/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital standard"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sw/strings.xml b/packages/SystemUI/customization/res/values-sw/strings.xml new file mode 100644 index 000000000000..e2ec3de573a8 --- /dev/null +++ b/packages/SystemUI/customization/res/values-sw/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Dijitali chaguomsingi"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ta/strings.xml b/packages/SystemUI/customization/res/values-ta/strings.xml new file mode 100644 index 000000000000..f4eea07b0aa5 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ta/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"டிஜிட்டல் இயல்பு"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-te/strings.xml b/packages/SystemUI/customization/res/values-te/strings.xml new file mode 100644 index 000000000000..c7c77d527e7f --- /dev/null +++ b/packages/SystemUI/customization/res/values-te/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"డిజిటల్ ఆటోమేటిక్ సెట్టింగ్"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-th/strings.xml b/packages/SystemUI/customization/res/values-th/strings.xml new file mode 100644 index 000000000000..61d880eb1ad9 --- /dev/null +++ b/packages/SystemUI/customization/res/values-th/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ดิจิทัลแบบเริ่มต้น"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-tl/strings.xml b/packages/SystemUI/customization/res/values-tl/strings.xml new file mode 100644 index 000000000000..a3484a7b6d2a --- /dev/null +++ b/packages/SystemUI/customization/res/values-tl/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Digital na default"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-tr/strings.xml b/packages/SystemUI/customization/res/values-tr/strings.xml new file mode 100644 index 000000000000..a90e9852ef2f --- /dev/null +++ b/packages/SystemUI/customization/res/values-tr/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Dijital varsayılan"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-uk/strings.xml b/packages/SystemUI/customization/res/values-uk/strings.xml new file mode 100644 index 000000000000..ee9b77b905a2 --- /dev/null +++ b/packages/SystemUI/customization/res/values-uk/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Цифровий, стандартний"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ur/strings.xml b/packages/SystemUI/customization/res/values-ur/strings.xml new file mode 100644 index 000000000000..06a6a7cd01fd --- /dev/null +++ b/packages/SystemUI/customization/res/values-ur/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"ڈیجیٹل ڈیفالٹ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-uz/strings.xml b/packages/SystemUI/customization/res/values-uz/strings.xml new file mode 100644 index 000000000000..6b31b048b4a1 --- /dev/null +++ b/packages/SystemUI/customization/res/values-uz/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Raqamli soat, standart"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-vi/strings.xml b/packages/SystemUI/customization/res/values-vi/strings.xml new file mode 100644 index 000000000000..830b6e2b16a1 --- /dev/null +++ b/packages/SystemUI/customization/res/values-vi/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Mặt số mặc định"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-zh-rCN/strings.xml b/packages/SystemUI/customization/res/values-zh-rCN/strings.xml new file mode 100644 index 000000000000..747567e9fb65 --- /dev/null +++ b/packages/SystemUI/customization/res/values-zh-rCN/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"默认数字"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-zh-rHK/strings.xml b/packages/SystemUI/customization/res/values-zh-rHK/strings.xml new file mode 100644 index 000000000000..c19cc68ff150 --- /dev/null +++ b/packages/SystemUI/customization/res/values-zh-rHK/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"數碼時鐘 (預設)"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-zh-rTW/strings.xml b/packages/SystemUI/customization/res/values-zh-rTW/strings.xml new file mode 100644 index 000000000000..6fcd313a291d --- /dev/null +++ b/packages/SystemUI/customization/res/values-zh-rTW/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"數位預設"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-zu/strings.xml b/packages/SystemUI/customization/res/values-zu/strings.xml new file mode 100644 index 000000000000..c87c250ae1b9 --- /dev/null +++ b/packages/SystemUI/customization/res/values-zu/strings.xml @@ -0,0 +1,22 @@ +<?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. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="clock_default_description" msgid="5309401440896597541">"Okuzenzakalelayo kwedijithali"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values/strings.xml b/packages/SystemUI/customization/res/values/strings.xml new file mode 100644 index 000000000000..897c842b6d4b --- /dev/null +++ b/packages/SystemUI/customization/res/values/strings.xml @@ -0,0 +1,25 @@ +<?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. + */ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- default clock face name [CHAR LIMIT=NONE]--> + <string name="clock_default_name">Default</string> + + <!-- default clock face description [CHAR LIMIT=NONE]--> + <string name="clock_default_description">Digital default</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt index b28920c590c5..b076b2cacf08 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt @@ -65,7 +65,13 @@ class DefaultClockController( protected var onSecondaryDisplay: Boolean = false override val events: DefaultClockEvents - override val config = ClockConfig(DEFAULT_CLOCK_ID) + override val config: ClockConfig by lazy { + ClockConfig( + DEFAULT_CLOCK_ID, + resources.getString(R.string.clock_default_name), + resources.getString(R.string.clock_default_description) + ) + } init { val parent = FrameLayout(ctx) 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 949641a7f75e..dd52e39488ac 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 @@ -25,7 +25,6 @@ import com.android.systemui.plugins.ClockProvider import com.android.systemui.plugins.ClockSettings private val TAG = DefaultClockProvider::class.simpleName -const val DEFAULT_CLOCK_NAME = "Default Clock" const val DEFAULT_CLOCK_ID = "DEFAULT" /** Provides the default system clock */ @@ -35,8 +34,7 @@ class DefaultClockProvider( val resources: Resources, val hasStepClockAnimation: Boolean = false ) : ClockProvider { - override fun getClocks(): List<ClockMetadata> = - listOf(ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME)) + override fun getClocks(): List<ClockMetadata> = listOf(ClockMetadata(DEFAULT_CLOCK_ID)) override fun createClock(settings: ClockSettings): ClockController { if (settings.clockId != DEFAULT_CLOCK_ID) { diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt index e2f4793b8f91..485c27e16150 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt @@ -192,15 +192,18 @@ enum class ClockTickRate(val value: Int) { /** Some data about a clock design */ data class ClockMetadata( val clockId: ClockId, - val name: String, -) { - constructor(clockId: ClockId) : this(clockId, clockId) {} -} +) /** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */ data class ClockConfig( val id: String, + /** Localized name of the clock */ + val name: String, + + /** Localized accessibility description for the clock */ + val description: String, + /** Transition to AOD should move smartspace like large clock instead of small clock */ val useAlternateSmartspaceAODTransition: Boolean = false, diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml index ec006c553b94..16eba220cf5d 100644 --- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -403,7 +403,7 @@ android:layout_height="wrap_content" android:layout_weight="1" android:layout_gravity="start|center_vertical" - android:orientation="vertical"> + android:orientation="horizontal"> <Button android:id="@+id/apm_button" android:layout_width="wrap_content" @@ -414,12 +414,7 @@ style="@style/Widget.Dialog.Button.BorderButton" android:clickable="true" android:focusable="true"/> - </LinearLayout> - <RelativeLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center_vertical"> <Button android:id="@+id/share_wifi_button" android:layout_width="wrap_content" @@ -430,8 +425,14 @@ android:ellipsize="end" android:clickable="true" android:focusable="true" - android:layout_alignParentLeft="true" android:visibility="gone"/> + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_gravity="end|center_vertical"> <Button android:id="@+id/done_button" android:layout_width="wrap_content" @@ -441,9 +442,8 @@ android:maxLines="1" android:ellipsize="end" android:clickable="true" - android:focusable="true" - android:layout_alignParentRight="true"/> - </RelativeLayout> + android:focusable="true"/> + </LinearLayout> </LinearLayout> </LinearLayout> diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml index b00908fd2bfa..c1bac3151049 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml @@ -15,7 +15,7 @@ --> <!-- Extends Framelayout --> -<com.android.systemui.statusbar.notification.row.FooterView +<com.android.systemui.statusbar.notification.footer.ui.view.FooterView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" @@ -76,4 +76,4 @@ /> </androidx.constraintlayout.widget.ConstraintLayout> </com.android.systemui.statusbar.AlphaOptimizedFrameLayout> -</com.android.systemui.statusbar.notification.row.FooterView> +</com.android.systemui.statusbar.notification.footer.ui.view.FooterView> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 937e97a5fc2b..24846d9ae16e 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stel versteknotasapp in Instellings"</string> <string name="install_app" msgid="5066668100199613936">"Installeer app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Sinkroniseer wedersyds na eksterne skerm?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Sinkroniseer skerm wedersyds"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Maak toe"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofoon en kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Onlangse appgebruik"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Sien onlangse toegang"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index de2fda491f78..23def2894368 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"በቅንብሮች ውስጥ ነባሪ የማስታወሻዎች መተግበሪያን ያቀናብሩ"</string> <string name="install_app" msgid="5066668100199613936">"መተግበሪያን ጫን"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ወደ ውጫዊ ማሳያ ይንጸባረቅ?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"ማሳያን አንጸባርቅ"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"አሰናብት"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"ማይክሮፎን እና ካሜራ"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"የቅርብ ጊዜ የመተግበሪያ አጠቃቀም"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"የቅርብ ጊዜ መዳረሻን አሳይ"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 79b671ccd4e9..80d63a23fd94 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"يمكنك ضبط تطبيق تدوين الملاحظات التلقائي في \"الإعدادات\"."</string> <string name="install_app" msgid="5066668100199613936">"تثبيت التطبيق"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"هل تريد بث محتوى جهازك على الشاشة الخارجية؟"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"بث المحتوى على الشاشة"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"إغلاق"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"الميكروفون والكاميرا"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"آخر استخدام في التطبيقات"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"عرض آخر استخدام في التطبيقات"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index ac30f182f521..c84577373919 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ছেটিঙত টোকাৰ ডিফ’ল্ট এপ্ ছেট কৰক"</string> <string name="install_app" msgid="5066668100199613936">"এপ্টো ইনষ্টল কৰক"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"বাহ্যিক ডিছপ্লে’লৈ মিৰ’ৰ কৰিবনে?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"ডিছপ্লে’ মিৰ’ৰ কৰক"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"অগ্ৰাহ্য কৰক"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"মাইক্ৰ’ফ’ন আৰু কেমেৰা"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"শেহতীয়া এপৰ ব্যৱহাৰ"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"শেহতীয়া এক্সেছ চাওক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 3ca61dc4f575..5aa26bac0687 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlarda defolt qeydlər tətbiqi ayarlayın"</string> <string name="install_app" msgid="5066668100199613936">"Tətbiqi quraşdırın"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Xarici displeyə əks etdirilsin?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Displeyi əks etdirin"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"İmtina edin"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon və kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Son tətbiq istifadəsi"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Son girişə baxın"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index b51d4b355b19..cd36884e4740 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Podesite podrazumevanu aplikaciju za beleške u Podešavanjima"</string> <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li da preslikate na spoljnji ekran?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Preslikaj ekran"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Odbaci"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon i kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedavno koristila aplikacija"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Prikaži nedavni pristup"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 35a84b0afee1..1b03c8ba09f6 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайце ў Наладах стандартную праграму для нататак"</string> <string name="install_app" msgid="5066668100199613936">"Усталяваць праграму"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Адлюстраваць на знешнім дысплеі?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Адлюстраваць дысплэй"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Закрыць"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Мікрафон і камера"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Нядаўна выкарыстоўваліся праграмамі"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Паглядзець нядаўні доступ"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 6b212e565a59..4ed1ad944045 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартно приложение за бележки от настройките"</string> <string name="install_app" msgid="5066668100199613936">"Инсталиране на приложението"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се дублира ли на външния екран?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Огледално копиране на дисплея"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Отхвърляне"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Скорошно използване на приложението"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Вижте скорошния достъп"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 5b5ac73430e3..426d38d68a0e 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"\'সেটিংস\' থেকে ডিফল্ট নোট নেওয়ার অ্যাপ সেট করুন"</string> <string name="install_app" msgid="5066668100199613936">"অ্যাপ ইনস্টল করুন"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"এক্সটার্নাল ডিসপ্লে আয়না?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"ডিসপ্লে দেখান"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"বাতিল করুন"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"মাইক্রোফোন ও ক্যামেরা"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"সম্প্রতি ব্যবহার করা অ্যাপ"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"সাম্প্রতিক অ্যাক্সেস দেখুন"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 33330b737edc..4eed7b8965ba 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u Postavkama"</string> <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Preslikati na vanjski ekran?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Preslikaj ekran"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Odbaci"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon i kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedavno korištenje aplikacije"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Prikaži nedavni pristup"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 45bb34253a86..b55a79ad8dd7 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defineix l\'aplicació de notes predeterminada a Configuració"</string> <string name="install_app" msgid="5066668100199613936">"Instal·la l\'aplicació"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vols replicar-ho a la pantalla externa?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Duplica la pantalla"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Ignora"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Micròfon i càmera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Ús recent de l\'aplicació"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Mostra l\'accés recent"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 0d7d23a34ef7..05b04191f6c7 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Výchozí aplikaci pro poznámky nastavíte v Nastavení"</string> <string name="install_app" msgid="5066668100199613936">"Nainstalovat aplikaci"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Zrcadlit na externí displej?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Zrcadlit displej"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Zavřít"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon a fotoaparát"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedávné použití aplikacemi"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Zobrazit nedávný přístup"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 4f6b88ec74b3..5971034b991c 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Angiv standardapp til noter i Indstillinger"</string> <string name="install_app" msgid="5066668100199613936">"Installer app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du spejle til ekstern skærm?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Spejl skærm"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Luk"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon og kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Seneste brug af apps"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Se seneste adgang"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 07aa14f400dc..c773f71d7786 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standard-Notizen-App in den Einstellungen einrichten"</string> <string name="install_app" msgid="5066668100199613936">"App installieren"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Auf externen Bildschirm spiegeln?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Bildschirm spiegeln"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Schließen"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon & Kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Kürzliche App-Nutzung"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Kürzliche Zugriffe ansehen"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 2a8e51cfbc7f..b6c95aa50bfd 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ορίστε την προεπιλεγμένη εφαρμογή σημειώσεων στις Ρυθμίσεις"</string> <string name="install_app" msgid="5066668100199613936">"Εγκατάσταση εφαρμογής"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Κατοπτρισμός σε εξωτερική οθόνη;"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Κατοπτρισμός οθόνης"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Παράβλεψη"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Μικρόφωνο και Κάμερα"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Πρόσφατη χρήση εφαρμογής"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Εμφάνιση πρόσφατης πρόσβασης"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 8647adb2934f..6c2b2307fccf 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string> <string name="install_app" msgid="5066668100199613936">"Install app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Dismiss"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone and Camera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app use"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"See recent access"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 8647adb2934f..6c2b2307fccf 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string> <string name="install_app" msgid="5066668100199613936">"Install app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Dismiss"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone and Camera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app use"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"See recent access"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 8647adb2934f..6c2b2307fccf 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string> <string name="install_app" msgid="5066668100199613936">"Install app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Dismiss"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone and Camera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app use"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"See recent access"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index d3ea858c3137..52514d22f927 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la app de notas predeterminada en Configuración"</string> <string name="install_app" msgid="5066668100199613936">"Instalar app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Quieres duplicar a la pantalla externa?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Duplicar pantalla"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Descartar"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrófono y cámara"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso reciente en apps"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ver accesos recientes"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 284fad4d5b89..4a3c06412802 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la aplicación de notas predeterminada en Ajustes"</string> <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Replicar en pantalla externa?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Replicar pantalla"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Cerrar"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrófono y cámara"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso reciente en aplicaciones"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ver acceso reciente"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 2b79ee5f09c1..08b489d11d7e 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Määrake seadetes märkmete vaikerakendus."</string> <string name="install_app" msgid="5066668100199613936">"Installi rakendus"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kas peegeldada välisekraanile?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Ekraani peegeldamine"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Loobu"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon ja kaamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Rakenduste hiljutine kasutamine"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Kuva hiljutine juurdepääs"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 68698ea2cc14..19495bccb4f8 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -676,8 +676,8 @@ <string name="group_system_go_back" msgid="8838454003680364227">"Atzera: itzuli aurreko egoerara (atzera egiteko botoia)"</string> <string name="group_system_access_home_screen" msgid="1857344316928441909">"Atzitu hasierako pantaila"</string> <string name="group_system_overview_open_apps" msgid="6897128761003265350">"Ikusi irekitako aplikazioen ikuspegi orokorra"</string> - <string name="group_system_cycle_forward" msgid="9202444850838205990">"Joan azken aplikazioetako batetik bestera (aurrera)"</string> - <string name="group_system_cycle_back" msgid="5163464503638229131">"Joan azken aplikazioetako batetik bestera (atzera)"</string> + <string name="group_system_cycle_forward" msgid="9202444850838205990">"Joan azkenaldian erabilitako aplikazio batetik bestera (aurrera)"</string> + <string name="group_system_cycle_back" msgid="5163464503638229131">"Joan azkenaldian erabilitako aplikazio batetik bestera (atzera)"</string> <string name="group_system_access_all_apps_search" msgid="488070738028991753">"Atzitu aplikazio guztien zerrenda eta bilatu (adibidez, bilatzeko aukeraren edo Exekutatzeko tresna aplikazioaren bidez)"</string> <string name="group_system_hide_reshow_taskbar" msgid="3809304065624351131">"Ezkutatu eta erakutsi (berriro) zereginen barra"</string> <string name="group_system_access_system_settings" msgid="7961639365383008053">"Atzitu sistemaren ezarpenak"</string> @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ezarri oharren aplikazio lehenetsia ezarpenetan"</string> <string name="install_app" msgid="5066668100199613936">"Instalatu aplikazioa"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kanpoko pantailan islatu nahi duzu?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Islatu pantaila"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Baztertu"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofonoa eta kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Aplikazioen azken erabilera"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ikusi azkenaldiko sarbidea"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 719924037534..68f6c1d9dd88 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"برنامه پیشفرض یادداشت را در «تنظیمات» تنظیم کنید"</string> <string name="install_app" msgid="5066668100199613936">"نصب برنامه"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"در نمایشگر خارجی پخش شود؟"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"بازتاباندن صفحهنمایش"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"بستن"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"میکروفون و دوربین"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"استفاده اخیر از برنامه"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"دیدن دسترسی اخیر"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 073ea60b28f4..934abad4b225 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Aseta oletusmuistiinpanosovellus Asetuksista"</string> <string name="install_app" msgid="5066668100199613936">"Asenna sovellus"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Peilataanko ulkoiselle näytölle?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Peilaa näyttö"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Ohita"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofoni ja kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Sovellusten viimeaikainen käyttö"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Katso viimeaikainen käyttö"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 52bcd7652af3..fe90569169d9 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir l\'application de prise de notes par défaut dans les Paramètres"</string> <string name="install_app" msgid="5066668100199613936">"Installer l\'application"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Dupliquer l\'écran sur un moniteur externe?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Dupliquer l\'écran"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Fermer"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone et appareil photo"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilisation récente par les applications"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Afficher l\'accès récent"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 4362d3c227fb..27a4bb6a0e1f 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir une appli de notes par défaut dans les paramètres"</string> <string name="install_app" msgid="5066668100199613936">"Installer l\'appli"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirroring sur écran externe ?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Dupliquer l\'écran"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Fermer"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Micro et caméra"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilisation récente par les applis"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Consulter les accès récents"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 1b836a8ea688..2056c2fba14b 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Establece a aplicación de notas predeterminada en Configuración"</string> <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Queres proxectar contido nunha pantalla externa?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Replicar pantalla"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Pechar"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrófono e cámara"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso recente por parte de aplicacións"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ver acceso recente"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 132ee2e73513..84be50a481e8 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"સેટિંગમાં નોંધની ડિફૉલ્ટ ઍપ સેટ કરો"</string> <string name="install_app" msgid="5066668100199613936">"ઍપ ઇન્સ્ટૉલ કરો"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"શું બાહ્ય ડિસ્પ્લે પર મિરર કરીએ?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"મિરર ડિસ્પ્લે"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"છોડી દો"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"માઇક્રોફોન અને કૅમેરા"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"તાજેતરનો ઍપનો વપરાશ"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"તાજેતરનો ઍક્સેસ મેનેજ કરો"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index f942de505920..2b0019f5274e 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग में जाकर, नोट लेने की सुविधा देने वाले ऐप्लिकेशन को डिफ़ॉल्ट के तौर पर सेट करें"</string> <string name="install_app" msgid="5066668100199613936">"ऐप्लिकेशन इंस्टॉल करें"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाहरी डिसप्ले को अन्य डिवाइस पर दिखाना है?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"मिरर डिसप्ले"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"खारिज करें"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"माइक्रोफ़ोन और कैमरा"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"हाल ही में इस्तेमाल करने वाला ऐप्लिकेशन"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"हाल में ऐक्सेस करने वाले ऐप"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index f7c68e160b63..23899fcb2110 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u postavkama"</string> <string name="install_app" msgid="5066668100199613936">"Instalacija"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li zrcaliti na vanjski zaslon?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Zrcaljenje zaslona"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Odbaci"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon i kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedavna upotreba aplikacije"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Pogledajte nedavni pristup"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index c1b38d904c4d..e5b17d9c6517 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Állítson be alapértelmezett jegyzetkészítő alkalmazást a Beállításokban"</string> <string name="install_app" msgid="5066668100199613936">"Alkalmazás telepítése"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Tükrözi a kijelzőt a külső képernyőre?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Kijelző tükrözése"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Elvetés"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon és kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Legutóbbi alkalmazáshasználat"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Legutóbbi hozzáférés"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 7139a1f844da..4a1c291e3d74 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Կարգավորեք նշումների կանխադրված հավելված Կարգավորումներում"</string> <string name="install_app" msgid="5066668100199613936">"Տեղադրել հավելվածը"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Հայելապատճենե՞լ արտաքին էկրանին"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Հայելապատճենել էկրանը"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Փակել"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Խոսափող և տեսախցիկ"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Հավելվածի վերջին օգտագործումը"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Տեսնել վերջին օգտագործումը"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 44aafde6f132..18a76686154f 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setel aplikasi catatan default di Setelan"</string> <string name="install_app" msgid="5066668100199613936">"Instal aplikasi"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Cerminkan ke layar eksternal?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Cerminkan layar"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Tutup"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon & Kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Penggunaan aplikasi baru-baru ini"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Lihat akses terbaru"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 1fda572ae10e..70bed4665e17 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stilltu sjálfgefið glósuforrit í stillingunum"</string> <string name="install_app" msgid="5066668100199613936">"Setja upp forrit"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spegla yfir á ytri skjá?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Spegla skjá"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Hunsa"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Hljóðnemi og myndavél"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nýlega notað af forriti"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Sjá nýlegan aðgang"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index ed8885f6e360..baffdb9778cd 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Imposta l\'app per le note predefinita nelle Impostazioni"</string> <string name="install_app" msgid="5066668100199613936">"Installa app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vuoi eseguire il mirroring al display esterno?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Esegui il mirroring del display"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Chiudi"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfono e fotocamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso recente da app"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Vedi accesso recente"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 51f5452d843f..968a98287275 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"צריך להגדיר את אפליקציית ברירת המחדל לפתקים ב\'הגדרות\'"</string> <string name="install_app" msgid="5066668100199613936">"התקנת האפליקציה"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"לשקף למסך חיצוני?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"תצוגת מראה"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"סגירה"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"מיקרופון ומצלמה"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"נעשה שימוש לאחרונה באפליקציות"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"צפייה בהרשאות הגישה האחרונות"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index e77aed9b1be7..798d42add510 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"[設定] でデフォルトのメモアプリを設定してください"</string> <string name="install_app" msgid="5066668100199613936">"アプリをインストール"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"外部ディスプレイにミラーリングしますか?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"ディスプレイをミラーリングする"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"閉じる"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"マイクとカメラ"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"最近のアプリの使用状況"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"最近のアクセスを表示"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 8d7deec249f8..f21a2a42536b 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"დააყენეთ ნაგულისხმევი შენიშვნების აპი პარამეტრებში"</string> <string name="install_app" msgid="5066668100199613936">"აპის ინსტალაცია"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"აირეკლოს გარე ეკრანზე?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"ეკრანის არეკვლა"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"დახურვა"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"მიკროფონი და კამერა"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"აპის ბოლოდროინდელი გამოყენება"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ბოლო წვდომის ნახვა"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index fc4fe8a2a26d..746c02ed780f 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден әдепкі жазба қолданбасын орнатыңыз."</string> <string name="install_app" msgid="5066668100199613936">"Қолданбаны орнату"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Сыртқы экран арқылы да көрсету керек пе?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Айна дисплей"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Қабылдамау"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон және камера"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Соңғы рет қолданбаның датчикті пайдалануы"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Соңғы рет пайдаланғандар"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 10c291dec4ab..9f3b99121b19 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"កំណត់កម្មវិធីកំណត់ចំណាំលំនាំដើមនៅក្នុងការកំណត់"</string> <string name="install_app" msgid="5066668100199613936">"ដំឡើងកម្មវិធី"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"បញ្ចាំងទៅឧបករណ៍បញ្ចាំងខាងក្រៅឬ?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"បញ្ចាំងទៅផ្ទាំងអេក្រង់"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"ច្រានចោល"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"មីក្រូហ្វូន និងកាមេរ៉ា"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"ការប្រើប្រាស់កម្មវិធីថ្មីៗនេះ"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"មើលការចូលប្រើនាពេលថ្មីៗនេះ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 77169809b914..79eef7295bc0 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಡೀಫಾಲ್ಟ್ ಟಿಪ್ಪಣಿಗಳ ಆ್ಯಪ್ ಅನ್ನು ಸೆಟ್ ಮಾಡಿ"</string> <string name="install_app" msgid="5066668100199613936">"ಆ್ಯಪ್ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ಬಾಹ್ಯ ಡಿಸ್ಪ್ಲೇಗೆ ಪ್ರತಿಬಿಂಬಿಸಬೇಕೆ?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"ಮಿರರ್ ಡಿಸ್ಪ್ಲೇ"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"ವಜಾಗೊಳಿಸಿ"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"ಮೈಕ್ರೊಫೋನ್ ಮತ್ತು ಕ್ಯಾಮರಾ"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್ ಬಳಕೆ"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ಇತ್ತೀಚಿನ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ನೋಡಿ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index c2fbf093160c..7985e4c7e3af 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"설정에서 기본 메모 앱 설정"</string> <string name="install_app" msgid="5066668100199613936">"앱 설치"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"외부 디스플레이로 미러링하시겠습니까?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"디스플레이 미러링"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"닫기"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"마이크 및 카메라"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"최근 앱 사용"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"최근 액세스 보기"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 8ab4cb7d9128..ded1f752ef87 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден демейки кыска жазуулар колдонмосун тууралаңыз"</string> <string name="install_app" msgid="5066668100199613936">"Колдонмону орнотуу"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Тышкы экранга чыгарасызбы?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Тышкы экран"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Жабуу"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон жана камера"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Жакында колдонмолордо иштетилген"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Акыркы пайдалануусун көрүү"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index a1585f2d69d7..1e61b8a85fb1 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ຕັ້ງຄ່າແອັບຈົດບັນທຶກເລີ່ມຕົ້ນໃນການຕັ້ງຄ່າ"</string> <string name="install_app" msgid="5066668100199613936">"ຕິດຕັ້ງແອັບ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ສາຍໃສ່ຈໍສະແດງຜົນພາຍນອກບໍ?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"ຈໍສະແດງຜົນແບບສະທ້ອນ"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"ປິດໄວ້"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"ໄມໂຄຣໂຟນ ແລະ ກ້ອງຖ່າຍຮູບ"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"ການໃຊ້ແອັບຫຼ້າສຸດ"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ເບິ່ງສິດເຂົ້າເຖິງຫຼ້າສຸດ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index c5f649c82dc0..06c1369d29ad 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nustatykite numatytąją užrašų programą Nustatymuose"</string> <string name="install_app" msgid="5066668100199613936">"Įdiegti programą"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Bendrinti ekrano vaizdą išoriniame ekrane?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Bendrinti ekrano vaizdą"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Atsisakyti"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofonas ir fotoaparatas"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Pastarasis programos naudojimas"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Žr. pastarąją prieigą"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index d49360919a32..fdf30285cee4 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Iestatījumos iestatiet noklusējuma piezīmju lietotni."</string> <string name="install_app" msgid="5066668100199613936">"Instalēt lietotni"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vai spoguļot ārējā displejā?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Spoguļot displeju"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Nerādīt"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofons un kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nesen izmantoja lietotnes"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Skatīt neseno piekļuvi"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 46193b3a6855..80ef7bb64d07 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Поставете стандардна апликација за белешки во „Поставки“"</string> <string name="install_app" msgid="5066668100199613936">"Инсталирајте ја апликацијата"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се синхронизира на надворешниот екран?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Пресликај екран"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Отфрли"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Неодамнешно користење на апликација"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Видете го скорешниот пристап"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index d63153882e72..5b1c80f37a18 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ക്രമീകരണത്തിൽ കുറിപ്പുകൾക്കുള്ള ഡിഫോൾട്ട് ആപ്പ് സജ്ജീകരിക്കുക"</string> <string name="install_app" msgid="5066668100199613936">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യൂ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ബാഹ്യ ഡിസ്പ്ലേയിലേക്ക് മിറർ ചെയ്യണോ?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"മിറർ ഡിസ്പ്ലേ"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"ഡിസ്മിസ് ചെയ്യുക"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"മൈക്രോഫോണും ക്യാമറയും"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"അടുത്തിടെയുള്ള ആപ്പ് ഉപയോഗം"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"അടുത്തിടെയുള്ള ആക്സസ് കാണുക"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index b16b22a4e041..3f65931f276e 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Тохиргоонд тэмдэглэлийн өгөгдмөл апп тохируулна уу"</string> <string name="install_app" msgid="5066668100199613936">"Аппыг суулгах"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Гадны дэлгэцэд тусгал үүсгэх үү?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Дэлгэцийн тусгал үүсгэх"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Хаах"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон болон камер"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Аппын саяхны ашиглалт"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Саяхны хандалтыг харах"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 16fac23db53f..238aacab4d32 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग्ज मध्ये डीफॉल्ट टिपा अॅप सेट करा"</string> <string name="install_app" msgid="5066668100199613936">"अॅप इंस्टॉल करा"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेवर मिरर करायचे आहे का?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"डिस्प्ले मिरर करा"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"डिसमिस करा"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"मायक्रोफोन आणि कॅमेरा"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"अलीकडील अॅप वापर"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"अलीकडील अॅक्सेस पहा"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 7cafdcde5e79..8c764f1e7f75 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Tetapkan apl nota lalai dalam Tetapan"</string> <string name="install_app" msgid="5066668100199613936">"Pasang apl"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Paparkan pada paparan luaran?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Segerakkan paparan"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Ketepikan"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon & Kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Penggunaan apl terbaharu"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Lihat akses terbaharu"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 620124eb5cec..883b9e95144a 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ဆက်တင်များတွင် မူရင်းမှတ်စုများအက်ပ် သတ်မှတ်ပါ"</string> <string name="install_app" msgid="5066668100199613936">"အက်ပ် ထည့်သွင်းရန်"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ပြင်ပဖန်သားပြင်သို့ စကရင်ပွားမလား။"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"ဖန်သားပြင်ကို စကရင်ပွားရန်"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"ပယ်ရန်"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"မိုက်ခရိုဖုန်းနှင့် ကင်မရာ"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"လတ်တလော အက်ပ်အသုံးပြုမှု"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"လတ်တလောအသုံးပြုမှုကို ကြည့်ရန်"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 722cc12d05f4..53a4c527cca6 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Du kan velge en standardapp for notater i Innstillinger"</string> <string name="install_app" msgid="5066668100199613936">"Installer appen"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du speile til en ekstern skjerm?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Speil skjermen"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Lukk"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon og kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nylig appbruk"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Se nylig tilgang"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 74e5c6f328f8..3b31b3adfd64 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिङमा गई नोट बनाउने डिफल्ट एप तोक्नुहोस्"</string> <string name="install_app" msgid="5066668100199613936">"एप इन्स्टल गर्नुहोस्"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेमा मिरर गर्ने हो?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"डिस्प्ले मिरर गर्नुहोस्"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"खारेज गर्नुहोस्"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"माइक्रोफोन तथा क्यामेरा"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"एपको हालसालैको प्रयोग"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"हालसालै एक्सेस गर्ने एप हेर्नुहोस्"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 6d97a9ffc805..664af5ec84eb 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standaard notitie-app instellen in Instellingen"</string> <string name="install_app" msgid="5066668100199613936">"App installeren"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spiegelen naar extern scherm?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Scherm spiegelen"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Sluiten"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfoon en camera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app-gebruik"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Recente toegang bekijken"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index a6e14f990820..db9e0c5debd8 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ସେଟିଂସରେ ଡିଫଲ୍ଟ ନୋଟ୍ସ ଆପ ସେଟ କରନ୍ତୁ"</string> <string name="install_app" msgid="5066668100199613936">"ଆପ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ଏକ୍ସଟର୍ନଲ ଡିସପ୍ଲେକୁ ମିରର କରିବେ?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"ଡିସପ୍ଲେ ମିରର କରନ୍ତୁ"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"ଖାରଜ କରନ୍ତୁ"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"ମାଇକ୍ରୋଫୋନ ଏବଂ କେମେରା"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"ବର୍ତ୍ତମାନର ଆପ ବ୍ୟବହାର"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ବର୍ତ୍ତମାନର ଆକ୍ସେସ ଦେଖନ୍ତୁ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index faca7b13eae1..591c5e781382 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਨੋਟ ਐਪ ਨੂੰ ਸੈੱਟ ਕਰੋ"</string> <string name="install_app" msgid="5066668100199613936">"ਐਪ ਸਥਾਪਤ ਕਰੋ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ਕੀ ਬਾਹਰੀ ਡਿਸਪਲੇ \'ਤੇ ਪ੍ਰਤਿਬਿੰਬਿਤ ਕਰਨਾ ਹੈ?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"ਡਿਸਪਲੇ ਨੂੰ ਪ੍ਰਤਿਬਿੰਬਿਤ ਕਰੋ"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"ਖਾਰਜ ਕਰੋ"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਅਤੇ ਕੈਮਰਾ"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"ਹਾਲ ਹੀ ਵਿੱਚ ਵਰਤੀ ਗਈ ਐਪ"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ਹਾਲੀਆ ਪਹੁੰਚ ਦੇਖੋ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 3bb539a21f6f..195122113140 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ustaw domyślną aplikację do obsługi notatek w Ustawieniach"</string> <string name="install_app" msgid="5066668100199613936">"Zainstaluj aplikację"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Powielić na wyświetlaczu zewnętrznym?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Powielaj obraz"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Zamknij"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon i aparat"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Aplikacje korzystające w ostatnim czasie"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Zobacz ostatni dostęp"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 8f93b73c3f85..693a3a1b7030 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string> <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Espelhar tela"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Dispensar"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfone e câmera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso recente do app"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Consultar acessos recentes"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 02ee09836610..c4f1f6790907 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Predefina a app de notas nas Definições"</string> <string name="install_app" msgid="5066668100199613936">"Instalar app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para o ecrã externo?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Espelhar ecrã"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Ignorar"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfone e câmara"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilização recente da app"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ver acesso recente"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 8f93b73c3f85..693a3a1b7030 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string> <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Espelhar tela"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Dispensar"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfone e câmera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso recente do app"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Consultar acessos recentes"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 14cdeaccdc5c..a942332e2472 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setează aplicația prestabilită de note din Setări"</string> <string name="install_app" msgid="5066668100199613936">"Instalează aplicația"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Oglindești pe ecranul extern?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Afișare în oglindă"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Închide"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfon și cameră"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilizare recentă în aplicații"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Vezi accesarea recentă"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index c5379c20b7ba..68601d6a71ce 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартное приложение для заметок в настройках."</string> <string name="install_app" msgid="5066668100199613936">"Установить приложение"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублировать на внешний дисплей?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Дублировать дисплей"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Закрыть"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Недавнее использование приложениями"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Посмотреть недавний доступ"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index d53f0eba6e4d..86cb3c324143 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"සැකසීම් තුළ පෙරනිමි සටහන් යෙදුම සකසන්න"</string> <string name="install_app" msgid="5066668100199613936">"යෙදුම ස්ථාපනය කරන්න"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"බාහිර සංදර්ශකයට දර්පණය කරන්න ද?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"සංදර්ශකය දර්පණය කරන්න"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"අස් කරන්න"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"මයික්රොෆෝනය සහ කැමරාව"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"මෑත යෙදුම් භාවිතය"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"මෑත ප්රවේශය බලන්න"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 7fa0d077918f..56b9f7549038 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavte predvolenú aplikáciu na poznámky v Nastaveniach"</string> <string name="install_app" msgid="5066668100199613936">"Inštalovať aplikáciu"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Chcete zrkadliť na externú obrazovku?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Zrkadliť obrazovku"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Zavrieť"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofón a fotoaparát"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedávne využitie aplikácie"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Zobraziť nedávny prístup"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 87c18f4cabed..b72f750eae7c 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavite privzeto aplikacijo za zapiske v nastavitvah."</string> <string name="install_app" msgid="5066668100199613936">"Namesti aplikacijo"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite zrcaliti v zunanji zaslon?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Zrcali zaslon"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Opusti"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon in fotoaparat"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedavna uporaba v aplikacijah"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ogled nedavnih dostopov"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 3e1471a68af2..92f6f9c27e77 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Cakto aplikacionin e parazgjedhur të shënimeve te \"Cilësimet\""</string> <string name="install_app" msgid="5066668100199613936">"Instalo aplikacionin"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Të pasqyrohet në ekranin e jashtëm?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Pasqyro ekranin"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Hiq"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofoni dhe kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Përdorimi i fundit i aplikacionit"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Shiko qasjen e fundit"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 07897d720128..7c0d9be76436 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Подесите подразумевану апликацију за белешке у Подешавањима"</string> <string name="install_app" msgid="5066668100199613936">"Инсталирај апликацију"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Желите ли да пресликате на спољњи екран?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Пресликај екран"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Одбаци"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Недавно користила апликација"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Прикажи недавни приступ"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index aee168e24329..323ce11f853d 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ställ in en standardapp för anteckningar i inställningarna"</string> <string name="install_app" msgid="5066668100199613936">"Installera appen"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vill du spegla till extern skärm?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Spegla skärm"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Ignorera"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon och kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Senaste appanvändning"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Se senaste åtkomst"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index be3baddbe912..304910a46526 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Teua programu chaguomsingi ya madokezo katika Mipangilio"</string> <string name="install_app" msgid="5066668100199613936">"Sakinisha programu"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Ungependa kuonyesha kwenye skrini ya nje?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Akisi skrini"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Ondoa"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Maikrofoni na Kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Matumizi ya programu hivi majuzi"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Angalia ufikiaji wa majuzi"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 785c4d5af8b6..3ac5e2e7c8cc 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"குறிப்பு எடுப்பதற்கான இயல்புநிலை ஆப்ஸை அமைப்புகளில் அமையுங்கள்"</string> <string name="install_app" msgid="5066668100199613936">"ஆப்ஸை நிறுவுங்கள்"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"வெளிப்புறக் காட்சிக்கு மிரர் செய்யவா?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"டிஸ்பிளேயை மிரர் செய்"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"வேண்டாம்"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"மைக்ரோஃபோனும் கேமராவும்"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"சமீபத்திய ஆப்ஸ் பயன்பாடு"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"சமீபத்திய அணுகலைக் காட்டு"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 96d77b7237ba..0526f95a8e84 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"సెట్టింగ్లలో ఆటోమేటిక్గా ఉండేలా ఒక నోట్స్ యాప్ను సెట్ చేసుకోండి"</string> <string name="install_app" msgid="5066668100199613936">"యాప్ను ఇన్స్టాల్ చేయండి"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"బాహ్య డిస్ప్లేను మిర్రర్ చేయాలా?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"మిర్రర్ డిస్ప్లే"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"విస్మరించండి"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"మైక్రోఫోన్ & కెమెరా"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"ఇటీవలి యాప్ వినియోగం"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ఇటీవలి యాక్సెస్ను చూడండి"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index f8fbfbe3c7d3..8949360f9508 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"กำหนดแอปการจดบันทึกเริ่มต้นในการตั้งค่า"</string> <string name="install_app" msgid="5066668100199613936">"ติดตั้งแอป"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"มิเรอร์ไปยังจอแสดงผลภายนอกไหม"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"มิเรอร์จอแสดงผล"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"ปิด"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"ไมโครโฟนและกล้อง"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"การใช้แอปครั้งล่าสุด"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ดูการเข้าถึงล่าสุด"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 435398db067d..e5c11df40e99 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Magtakda ng default na app sa pagtatala sa Mga Setting"</string> <string name="install_app" msgid="5066668100199613936">"I-install ang app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"I-mirror sa external na display?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"I-mirror ang display"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"I-dismiss"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikropono at Camera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Kamakailang paggamit ng app"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Tingnan ang kamakailang access"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index d0ddbec98faf..3552d9214fb0 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlar\'ı kullanarak varsayılan notlar ayarlayın"</string> <string name="install_app" msgid="5066668100199613936">"Uygulamayı yükle"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Harici ekrana yansıtılsın mı?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Ekranı yansıt"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Kapat"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon ve Kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Son uygulama kullanımı"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Son erişimi göster"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 1489dc77a9f1..2e6aea9d59d3 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Призначте стандартний додаток для нотаток у налаштуваннях"</string> <string name="install_app" msgid="5066668100199613936">"Установити додаток"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублювати на зовнішньому екрані?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Дублювати екран"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Закрити"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Мікрофон і камера"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Нещодавнє використання додатками"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Переглянути нещодавній доступ"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 9d69a5e13319..2e2fc418116d 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ترتیبات میں ڈیفالٹ نوٹس ایپ سیٹ کریں"</string> <string name="install_app" msgid="5066668100199613936">"ایپ انسٹال کریں"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"بیرونی ڈسپلے پر مرر کریں؟"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"ڈسپلے کو دو طرفہ مطابقت پذیر بنائیں"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"برخاست کریں"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"مائیکروفون اور کیمرا"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"حالیہ ایپ کا استعمال"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"حالیہ رسائی دیکھیں"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 31b216b8977f..a8654d5604b1 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standart qaydlar ilovasini Sozlamalar orqali tanlang"</string> <string name="install_app" msgid="5066668100199613936">"Ilovani oʻrnatish"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Tashqi displeyda aks ettirilsinmi?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Displeyni akslantirish"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Yopish"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon va kamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Ilovadan oxirgi foydalanish"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Oxirgi ruxsatni koʻrish"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 814e0a6087eb..54437456188f 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Đặt ứng dụng ghi chú mặc định trong phần Cài đặt"</string> <string name="install_app" msgid="5066668100199613936">"Cài đặt ứng dụng"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Đồng bộ hoá hai chiều sang màn hình ngoài?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Phản chiếu màn hình"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Đóng"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrô và máy ảnh"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Hoạt động sử dụng gần đây của ứng dụng"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Xem hoạt động truy cập gần đây"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 8b2caf028b5e..44c163b03bcb 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在设置中设置默认记事应用"</string> <string name="install_app" msgid="5066668100199613936">"安装应用"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"镜像到外接显示屏?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"镜像显示"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"关闭"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"麦克风和摄像头"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"近期应用对手机传感器的使用情况"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"查看近期使用情况"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 8a160c366f74..f45b2fe1fc39 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設筆記應用程式"</string> <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要鏡像投射至外部顯示屏嗎?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"鏡像顯示"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"關閉"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"麥克風和相機"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"近期應用程式使用情況"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"查看近期存取記錄"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 38b81a0a4dee..5a5bb9d19c3f 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設記事應用程式"</string> <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要以鏡像方式投放至外部螢幕嗎?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"鏡像顯示"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"關閉"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"麥克風和相機"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"最近曾使用感應器的應用程式"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"查看近期存取記錄"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index fc704172a295..8b6bfae60199 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -1183,10 +1183,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setha i-app yamanothi azenzakalelayo Kumsethingi"</string> <string name="install_app" msgid="5066668100199613936">"Faka i-app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Fanisa nesibonisi sangaphandle?"</string> - <!-- no translation found for mirror_display (2515262008898122928) --> - <skip /> - <!-- no translation found for dismiss_dialog (2195508495854675882) --> - <skip /> + <string name="mirror_display" msgid="2515262008898122928">"Isibonisi sokufanisa"</string> + <string name="dismiss_dialog" msgid="2195508495854675882">"Chitha"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"Imakrofoni Nekhamera"</string> <string name="privacy_dialog_summary" msgid="2458769652125995409">"Ukusetshenziswa kwakamuva kwe-app"</string> <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Bona ukufinyelela kwakamuva"</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 0ee5da22a31b..6d54058f8e0c 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -846,7 +846,7 @@ <!-- Amount the button should shake when it's not long-pressed for long enough. --> <dimen name="keyguard_affordance_shake_amplitude">8dp</dimen> - <dimen name="keyguard_affordance_horizontal_offset">32dp</dimen> + <dimen name="keyguard_affordance_horizontal_offset">16dp</dimen> <dimen name="keyguard_affordance_vertical_offset">32dp</dimen> <!-- Value should be at least sum of 'keyguard_affordance_width' + 'keyguard_affordance_horizontal_offset' --> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java index 5d036fbe5e52..b44bf395930e 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java @@ -71,7 +71,6 @@ public class FloatingRotationButton implements RotationButton { private AnimatedVectorDrawable mAnimatedDrawable; private boolean mIsShowing; - private boolean mCanShow = true; private int mDisplayRotation; private boolean mIsTaskbarVisible = false; @@ -150,7 +149,7 @@ public class FloatingRotationButton implements RotationButton { @Override public boolean show() { - if (!mCanShow || mIsShowing) { + if (mIsShowing) { return false; } @@ -222,14 +221,6 @@ public class FloatingRotationButton implements RotationButton { } @Override - public void setCanShowRotationButton(boolean canShow) { - mCanShow = canShow; - if (!mCanShow) { - hide(); - } - } - - @Override public void onTaskbarStateChanged(boolean taskbarVisible, boolean taskbarStashed) { mIsTaskbarVisible = taskbarVisible; mIsTaskbarStashed = taskbarStashed; diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java index 89f71ebf3dce..42dda0a4da4f 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java @@ -36,7 +36,6 @@ public interface RotationButton { default boolean isVisible() { return false; } - default void setCanShowRotationButton(boolean canShow) {} default void onTaskbarStateChanged(boolean taskbarVisible, boolean taskbarStashed) {} default void updateIcon(int lightIconColor, int darkIconColor) { } default void setOnClickListener(View.OnClickListener onClickListener) { } 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 0094820f0dad..a6e04cec5f86 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 @@ -23,6 +23,7 @@ import android.view.SurfaceControl; import android.window.PictureInPictureSurfaceTransaction; import android.window.TaskSnapshot; +import com.android.internal.os.IResultReceiver; import com.android.systemui.shared.recents.model.ThumbnailData; public class RecentsAnimationControllerCompat { @@ -89,11 +90,16 @@ public class RecentsAnimationControllerCompat { * @param sendUserLeaveHint determines whether userLeaveHint will be set true to the previous * app. */ - public void finish(boolean toHome, boolean sendUserLeaveHint) { + public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) { try { - mAnimationController.finish(toHome, sendUserLeaveHint); + mAnimationController.finish(toHome, sendUserLeaveHint, finishCb); } catch (RemoteException e) { Log.e(TAG, "Failed to finish recents animation", e); + try { + finishCb.send(0, null); + } catch (Exception ex) { + // Local call, can ignore + } } } diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index bb0cf6d470a2..eb7a7358cbf1 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -34,7 +34,6 @@ import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.customization.R import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.dagger.qualifiers.DisplaySpecific import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags.DOZING_MIGRATION_1 @@ -80,8 +79,8 @@ constructor( private val batteryController: BatteryController, private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val configurationController: ConfigurationController, - @DisplaySpecific private val resources: Resources, - @DisplaySpecific private val context: Context, + @Main private val resources: Resources, + private val context: Context, @Main private val mainExecutor: DelayableExecutor, @Background private val bgExecutor: Executor, @KeyguardSmallClockLog private val smallLogBuffer: LogBuffer?, @@ -212,13 +211,13 @@ constructor( if (regionSamplingEnabled) { clock?.let { clock -> smallRegionSampler?.let { - smallClockIsDark = it.currentRegionDarkness().isDark - clock.smallClock.events.onRegionDarknessChanged(smallClockIsDark) + val isRegionDark = it.currentRegionDarkness().isDark + clock.smallClock.events.onRegionDarknessChanged(isRegionDark) } largeRegionSampler?.let { - largeClockIsDark = it.currentRegionDarkness().isDark - clock.largeClock.events.onRegionDarknessChanged(largeClockIsDark) + val isRegionDark = it.currentRegionDarkness().isDark + clock.largeClock.events.onRegionDarknessChanged(isRegionDark) } } return @@ -226,12 +225,12 @@ constructor( val isLightTheme = TypedValue() context.theme.resolveAttribute(android.R.attr.isLightTheme, isLightTheme, true) - smallClockIsDark = isLightTheme.data == 0 - largeClockIsDark = isLightTheme.data == 0 + val isRegionDark = isLightTheme.data == 0 clock?.run { - smallClock.events.onRegionDarknessChanged(smallClockIsDark) - largeClock.events.onRegionDarknessChanged(largeClockIsDark) + Log.i(TAG, "Region isDark: $isRegionDark") + smallClock.events.onRegionDarknessChanged(isRegionDark) + largeClock.events.onRegionDarknessChanged(isRegionDark) } } protected open fun createRegionSampler( @@ -261,9 +260,6 @@ constructor( get() = isKeyguardVisible && dozeAmount < DOZE_TICKRATE_THRESHOLD private var cachedWeatherData: WeatherData? = null - private var smallClockIsDark = true - private var largeClockIsDark = true - private val configListener = object : ConfigurationController.ConfigurationListener { override fun onThemeChanged() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java index 51c0676876b9..50be97ec1af9 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java @@ -139,7 +139,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView { case PROMPT_REASON_USER_REQUEST: return R.string.kg_prompt_after_user_lockdown_password; case PROMPT_REASON_PREPARE_FOR_UPDATE: - return R.string.kg_prompt_unattended_update_password; + return R.string.kg_prompt_reason_timeout_password; case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT: return R.string.kg_prompt_reason_timeout_password; case PROMPT_REASON_TRUSTAGENT_EXPIRED: diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index 714ba81fc664..57151ae32db0 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -321,7 +321,7 @@ public class KeyguardPatternViewController resId = R.string.kg_prompt_after_user_lockdown_pattern; break; case PROMPT_REASON_PREPARE_FOR_UPDATE: - resId = R.string.kg_prompt_unattended_update_pattern; + resId = R.string.kg_prompt_reason_timeout_pattern; break; case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT: resId = R.string.kg_prompt_reason_timeout_pattern; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java index 9d6d0332b96b..681aa70402bd 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -123,7 +123,7 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView case PROMPT_REASON_USER_REQUEST: return R.string.kg_prompt_after_user_lockdown_pin; case PROMPT_REASON_PREPARE_FOR_UPDATE: - return R.string.kg_prompt_unattended_update_pin; + return R.string.kg_prompt_reason_timeout_pin; case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT: return R.string.kg_prompt_reason_timeout_pin; case PROMPT_REASON_TRUSTAGENT_EXPIRED: diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index f9cc03eea288..d8486029a903 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -18,7 +18,6 @@ package com.android.keyguard; import static java.util.Collections.emptySet; -import android.animation.LayoutTransition; import android.content.Context; import android.graphics.Canvas; import android.os.Build; @@ -79,14 +78,6 @@ public class KeyguardStatusView extends GridLayout { mKeyguardSlice = findViewById(R.id.keyguard_slice_view); mMediaHostContainer = findViewById(R.id.status_view_media_container); - if (mMediaHostContainer != null) { - LayoutTransition mediaLayoutTransition = new LayoutTransition(); - ((ViewGroup) mMediaHostContainer).setLayoutTransition(mediaLayoutTransition); - mediaLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING); - mediaLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING); - mediaLayoutTransition.disableTransitionType(LayoutTransition.APPEARING); - mediaLayoutTransition.disableTransitionType(LayoutTransition.DISAPPEARING); - } updateDark(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index 67b705222977..79642bdae1ce 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -23,7 +23,6 @@ import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_CL import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; import android.animation.Animator; -import android.animation.LayoutTransition; import android.animation.ValueAnimator; import android.annotation.Nullable; import android.content.res.Configuration; @@ -50,14 +49,15 @@ import com.android.internal.jank.InteractionJankMonitor; import com.android.keyguard.KeyguardClockSwitch.ClockSize; import com.android.keyguard.logging.KeyguardLogger; import com.android.systemui.Dumpable; -import com.android.systemui.res.R; +import com.android.systemui.animation.ViewHierarchyAnimator; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; -import com.android.systemui.power.shared.model.ScreenPowerState; import com.android.systemui.plugins.ClockController; import com.android.systemui.power.domain.interactor.PowerInteractor; +import com.android.systemui.power.shared.model.ScreenPowerState; +import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.PropertyAnimator; import com.android.systemui.statusbar.notification.stack.AnimationProperties; @@ -175,27 +175,10 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV return; } - final LayoutTransition mediaLayoutTransition = - ((ViewGroup) mediaHostContainer).getLayoutTransition(); - if (mediaLayoutTransition == null) return; - - mediaLayoutTransition.enableTransitionType(LayoutTransition.CHANGING); + ViewHierarchyAnimator.Companion.animateNextUpdate(mediaHostContainer, + Interpolators.STANDARD, /* duration= */ 500L, + /* animateChildren= */ false); }); - - mediaHostContainer.addOnLayoutChangeListener( - (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { - final LayoutTransition mediaLayoutTransition = - ((ViewGroup) mediaHostContainer).getLayoutTransition(); - if (mediaLayoutTransition == null) return; - if (!mediaLayoutTransition.isTransitionTypeEnabled( - LayoutTransition.CHANGING)) { - return; - } - // Note: when this is called, the LayoutTransition is already been set up. - // Disables the LayoutTransition until it's explicitly enabled again. - mediaLayoutTransition.disableTransitionType(LayoutTransition.CHANGING); - } - ); } mDumpManager.registerDumpable(getInstanceName(), this); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 3f5ec7d020da..3bf148276eab 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -189,6 +189,8 @@ import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.util.Assert; import com.android.systemui.util.settings.SecureSettings; +import dalvik.annotation.optimization.NeverCompile; + import com.google.android.collect.Lists; import java.io.PrintWriter; @@ -4430,6 +4432,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } @SuppressLint("MissingPermission") + @NeverCompile @Override public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { pw.println("KeyguardUpdateMonitor state:"); diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index a7b35ef3aba4..0d3f726b011b 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -62,6 +62,7 @@ import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.AuthRippleController; import com.android.systemui.biometrics.UdfpsController; import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams; +import com.android.systemui.bouncer.domain.interactor.BouncerInteractor; import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; @@ -74,12 +75,15 @@ import com.android.systemui.keyguard.shared.model.TransitionStep; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.res.R; +import com.android.systemui.scene.shared.flag.SceneContainerFlags; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.DelayableExecutor; +import dagger.Lazy; + import java.io.PrintWriter; import java.util.Objects; import java.util.function.Consumer; @@ -128,6 +132,8 @@ public class LockIconViewController implements Dumpable { @NonNull private final KeyguardTransitionInteractor mTransitionInteractor; @NonNull private final KeyguardInteractor mKeyguardInteractor; @NonNull private final View.AccessibilityDelegate mAccessibilityDelegate; + @NonNull private final Lazy<BouncerInteractor> mBouncerInteractor; + @NonNull private final SceneContainerFlags mSceneContainerFlags; // Tracks the velocity of a touch to help filter out the touches that move too fast. private VelocityTracker mVelocityTracker; @@ -204,7 +210,9 @@ public class LockIconViewController implements Dumpable { @NonNull KeyguardInteractor keyguardInteractor, @NonNull FeatureFlags featureFlags, PrimaryBouncerInteractor primaryBouncerInteractor, - Context context + Context context, + Lazy<BouncerInteractor> bouncerInteractor, + SceneContainerFlags sceneContainerFlags ) { mStatusBarStateController = statusBarStateController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; @@ -233,6 +241,8 @@ public class LockIconViewController implements Dumpable { dumpManager.registerDumpable(TAG, this); mResources = resources; mContext = context; + mBouncerInteractor = bouncerInteractor; + mSceneContainerFlags = sceneContainerFlags; mAccessibilityDelegate = new View.AccessibilityDelegate() { private final AccessibilityNodeInfo.AccessibilityAction mAccessibilityAuthenticateHint = @@ -715,7 +725,8 @@ public class LockIconViewController implements Dumpable { return mDownDetected; } - private void onLongPress() { + @VisibleForTesting + protected void onLongPress() { cancelTouches(); if (mFalsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)) { Log.v(TAG, "lock icon long-press rejected by the falsing manager."); @@ -732,7 +743,11 @@ public class LockIconViewController implements Dumpable { // play device entry haptic (consistent with UDFPS controller longpress) vibrateOnLongPress(); - mKeyguardViewController.showPrimaryBouncer(/* scrim */ true); + if (mSceneContainerFlags.isEnabled()) { + mBouncerInteractor.get().showOrUnlockDevice(null); + } else { + mKeyguardViewController.showPrimaryBouncer(/* scrim */ true); + } } diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 018038423d4e..7739021bad33 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -87,7 +87,6 @@ import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.logging.NotificationLogger; -import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager; import com.android.systemui.statusbar.phone.AutoHideController; @@ -130,14 +129,14 @@ import com.android.systemui.util.leak.LeakDetector; import com.android.systemui.util.leak.LeakReporter; import com.android.systemui.util.sensors.AsyncSensorManager; +import dagger.Lazy; + import java.util.concurrent.Executor; import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Named; -import dagger.Lazy; - /** * Class to handle ugly dependencies throughout sysui until we determine the * long-term dependency injection solution. @@ -298,7 +297,6 @@ public class Dependency { @Inject Lazy<AccessibilityFloatingMenuController> mAccessibilityFloatingMenuController; @Inject Lazy<StatusBarStateController> mStatusBarStateController; @Inject Lazy<NotificationLockscreenUserManager> mNotificationLockscreenUserManager; - @Inject Lazy<NotificationGutsManager> mNotificationGutsManager; @Inject Lazy<NotificationMediaManager> mNotificationMediaManager; @Inject Lazy<NotificationRemoteInputManager> mNotificationRemoteInputManager; @Inject Lazy<SmartReplyConstants> mSmartReplyConstants; @@ -498,7 +496,6 @@ public class Dependency { mProviders.put(NotificationLockscreenUserManager.class, mNotificationLockscreenUserManager::get); mProviders.put(NotificationMediaManager.class, mNotificationMediaManager::get); - mProviders.put(NotificationGutsManager.class, mNotificationGutsManager::get); mProviders.put(NotificationRemoteInputManager.class, mNotificationRemoteInputManager::get); mProviders.put(SmartReplyConstants.class, mSmartReplyConstants::get); diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java index 4541384aaa37..b573fadea15e 100644 --- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java +++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java @@ -28,6 +28,7 @@ import com.android.systemui.res.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEventLogger; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.qs.QSUserSwitcherEvent; import com.android.systemui.settings.UserTracker; @@ -46,6 +47,7 @@ import dagger.assisted.AssistedInject; /** * Manages notification when a guest session is resumed. */ +@SysUISingleton public class GuestResumeSessionReceiver { @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 4af2c740ddc9..54dbf7275dce 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -93,6 +93,8 @@ import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.ThreadFactory; import com.android.systemui.util.settings.SecureSettings; +import dalvik.annotation.optimization.NeverCompile; + import kotlin.Pair; import java.io.PrintWriter; @@ -1088,6 +1090,7 @@ public class ScreenDecorations implements CoreStartable, Dumpable { } } + @NeverCompile @Override public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { pw.println("ScreenDecorations state:"); diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt index f6e02969e4c2..53b6879db3d7 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt @@ -15,7 +15,10 @@ interface CommunalRepository { class CommunalRepositoryImpl @Inject constructor( - featureFlags: FeatureFlagsClassic, + private val featureFlags: FeatureFlagsClassic, ) : CommunalRepository { - override val isCommunalEnabled = featureFlags.isEnabled(Flags.COMMUNAL_SERVICE_ENABLED) + override val isCommunalEnabled: Boolean + get() = + featureFlags.isEnabled(Flags.COMMUNAL_SERVICE_ENABLED) && + featureFlags.isEnabled(Flags.COMMUNAL_HUB) } diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt index 9fb8da3e76af..04bb6ae75e60 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt @@ -28,11 +28,13 @@ import kotlinx.coroutines.flow.Flow class CommunalInteractor @Inject constructor( - communalRepository: CommunalRepository, + private val communalRepository: CommunalRepository, widgetRepository: CommunalWidgetRepository, ) { + /** Whether communal features are enabled. */ - val isCommunalEnabled: Boolean = communalRepository.isCommunalEnabled + val isCommunalEnabled: Boolean + get() = communalRepository.isCommunalEnabled /** A flow of info about the widget to be displayed, or null if widget is unavailable. */ val appWidgetInfo: Flow<CommunalAppWidgetInfo?> = widgetRepository.stopwatchAppWidgetInfo diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 4b6ad6d9be03..d5f0e649ef40 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -56,6 +56,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FlagsModule; import com.android.systemui.keyboard.KeyboardModule; +import com.android.systemui.keyevent.data.repository.KeyEventRepositoryModule; import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule; import com.android.systemui.log.dagger.LogModule; import com.android.systemui.log.dagger.MonitorLog; @@ -181,6 +182,7 @@ import javax.inject.Named; FalsingModule.class, FlagsModule.class, FooterActionsModule.class, + KeyEventRepositoryModule.class, KeyboardModule.class, KeyguardBlueprintModule.class, LetterboxModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt index 5b85ad01301b..1e29e1fa3197 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt @@ -2,7 +2,7 @@ package com.android.systemui.deviceentry.data.repository import com.android.internal.widget.LockPatternUtils import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow +import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background @@ -51,7 +51,7 @@ interface DeviceEntryRepository { * When this is `false`, an automatically-triggered face unlock shouldn't automatically dismiss * the lockscreen. */ - fun isBypassEnabled(): Boolean + val isBypassEnabled: StateFlow<Boolean> } /** Encapsulates application state for device entry. */ @@ -68,7 +68,7 @@ constructor( ) : DeviceEntryRepository { override val isUnlocked = - ConflatedCallbackFlow.conflatedCallbackFlow { + conflatedCallbackFlow { val callback = object : KeyguardStateController.Callback { override fun onUnlockedChanged() { @@ -112,7 +112,24 @@ constructor( } } - override fun isBypassEnabled() = keyguardBypassController.bypassEnabled + override val isBypassEnabled: StateFlow<Boolean> = + conflatedCallbackFlow { + val listener = + object : KeyguardBypassController.OnBypassStateChangedListener { + override fun onBypassStateChanged(isEnabled: Boolean) { + trySend(isEnabled) + } + } + keyguardBypassController.registerOnBypassStateChangedListener(listener) + awaitClose { + keyguardBypassController.unregisterOnBypassStateChangedListener(listener) + } + } + .stateIn( + applicationScope, + SharingStarted.Eagerly, + initialValue = keyguardBypassController.bypassEnabled, + ) companion object { private const val TAG = "DeviceEntryRepositoryImpl" 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 5612c9a488ff..e96e318fd59d 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 @@ -106,5 +106,5 @@ constructor( * authentication challenge via face unlock or fingerprint sensor can automatically bypass the * lock screen. */ - fun isBypassEnabled() = repository.isBypassEnabled() + val isBypassEnabled: StateFlow<Boolean> = repository.isBypassEnabled } diff --git a/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepository.kt b/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepository.kt new file mode 100644 index 000000000000..5bc5d0b290ca --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepository.kt @@ -0,0 +1,56 @@ +/* + * 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 com.android.systemui.keyevent.data.repository + +import android.view.KeyEvent +import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging +import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.CommandQueue +import javax.inject.Inject +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow + +/** Defines interface for classes that encapsulate application state for key event presses. */ +interface KeyEventRepository { + /** Observable for whether the power button key is pressed/down or not. */ + val isPowerButtonDown: Flow<Boolean> +} + +@SysUISingleton +class KeyEventRepositoryImpl +@Inject +constructor( + val commandQueue: CommandQueue, +) : KeyEventRepository { + override val isPowerButtonDown: Flow<Boolean> = conflatedCallbackFlow { + val callback = + object : CommandQueue.Callbacks { + override fun handleSystemKey(event: KeyEvent) { + if (event.keyCode == KeyEvent.KEYCODE_POWER) { + trySendWithFailureLogging(event.isDown, TAG, "updated isPowerButtonDown") + } + } + } + commandQueue.addCallback(callback) + awaitClose { commandQueue.removeCallback(callback) } + } + + companion object { + private const val TAG = "KeyEventRepositoryImpl" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepositoryModule.kt new file mode 100644 index 000000000000..afba5dbd84c1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepositoryModule.kt @@ -0,0 +1,25 @@ +/* + * 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 com.android.systemui.keyevent.data.repository + +import dagger.Binds +import dagger.Module + +@Module +interface KeyEventRepositoryModule { + @Binds fun keyEventRepository(impl: KeyEventRepositoryImpl): KeyEventRepository +} diff --git a/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt index 3f2f67dbba37..9949fa589cd5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt @@ -13,55 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.android.systemui.keyevent.domain.interactor -import android.view.KeyEvent -import com.android.systemui.back.domain.interactor.BackActionInteractor import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.keyguard.domain.interactor.KeyguardKeyEventInteractor +import com.android.systemui.keyevent.data.repository.KeyEventRepository import javax.inject.Inject /** - * Sends key events to the appropriate interactors and then acts upon key events that haven't - * already been handled but should be handled by SystemUI. + * Business logic for all key event state. This includes all key events, regardless of whether + * they've been handled or not by a consumer. + * + * For key events that SysUI wants to properly handle, see [SysUIKeyEventHandler]. */ @SysUISingleton class KeyEventInteractor @Inject constructor( - private val backActionInteractor: BackActionInteractor, - private val keyguardKeyEventInteractor: KeyguardKeyEventInteractor, + repository: KeyEventRepository, ) { - fun dispatchKeyEvent(event: KeyEvent): Boolean { - if (keyguardKeyEventInteractor.dispatchKeyEvent(event)) { - return true - } - - when (event.keyCode) { - KeyEvent.KEYCODE_BACK -> { - if (event.handleAction()) { - backActionInteractor.onBackRequested() - } - return true - } - } - return false - } - - fun interceptMediaKey(event: KeyEvent): Boolean { - return keyguardKeyEventInteractor.interceptMediaKey(event) - } - - fun dispatchKeyEventPreIme(event: KeyEvent): Boolean { - return keyguardKeyEventInteractor.dispatchKeyEventPreIme(event) - } - - companion object { - // Most actions shouldn't be handled on the down event and instead handled on subsequent - // key events like ACTION_UP. - fun KeyEvent.handleAction(): Boolean { - return action != KeyEvent.ACTION_DOWN - } - } + val isPowerButtonDown = repository.isPowerButtonDown } diff --git a/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt new file mode 100644 index 000000000000..1febc79b8241 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt @@ -0,0 +1,69 @@ +/* + * 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 com.android.systemui.keyevent.domain.interactor + +import android.view.KeyEvent +import com.android.systemui.back.domain.interactor.BackActionInteractor +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.KeyguardKeyEventInteractor +import javax.inject.Inject + +/** + * Sends key events to the appropriate interactors and then acts upon key events that haven't + * already been handled but should be handled by SystemUI. + * + * To observe any key event states, see [KeyEventInteractor]. + */ +@SysUISingleton +class SysUIKeyEventHandler +@Inject +constructor( + private val backActionInteractor: BackActionInteractor, + private val keyguardKeyEventInteractor: KeyguardKeyEventInteractor, +) { + fun dispatchKeyEvent(event: KeyEvent): Boolean { + if (keyguardKeyEventInteractor.dispatchKeyEvent(event)) { + return true + } + + when (event.keyCode) { + KeyEvent.KEYCODE_BACK -> { + if (event.handleAction()) { + backActionInteractor.onBackRequested() + } + return true + } + } + return false + } + + fun interceptMediaKey(event: KeyEvent): Boolean { + return keyguardKeyEventInteractor.interceptMediaKey(event) + } + + fun dispatchKeyEventPreIme(event: KeyEvent): Boolean { + return keyguardKeyEventInteractor.dispatchKeyEventPreIme(event) + } + + companion object { + // Most actions shouldn't be handled on the down event and instead handled on subsequent + // key events like ACTION_UP. + fun KeyEvent.handleAction(): Boolean { + return action != KeyEvent.ACTION_DOWN + } + } +} 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 d69876292024..6d084563cbb3 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 @@ -21,7 +21,7 @@ import android.media.AudioManager import android.view.KeyEvent import com.android.systemui.back.domain.interactor.BackActionInteractor import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor.Companion.handleAction +import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler.Companion.handleAction import com.android.systemui.media.controls.util.MediaSessionLegacyHelperWrapper import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.power.domain.interactor.PowerInteractor @@ -29,15 +29,16 @@ import com.android.systemui.shade.ShadeController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi /** Handles key events arriving when the keyguard is showing or device is dozing. */ +@ExperimentalCoroutinesApi @SysUISingleton class KeyguardKeyEventInteractor @Inject constructor( private val context: Context, private val statusBarStateController: StatusBarStateController, - private val keyguardInteractor: KeyguardInteractor, private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager, private val shadeController: ShadeController, private val mediaSessionLegacyHelperWrapper: MediaSessionLegacyHelperWrapper, @@ -56,7 +57,11 @@ constructor( if (event.handleAction()) { when (event.keyCode) { KeyEvent.KEYCODE_MENU -> return dispatchMenuKeyEvent() - KeyEvent.KEYCODE_SPACE -> return dispatchSpaceEvent() + KeyEvent.KEYCODE_SPACE, + KeyEvent.KEYCODE_ENTER -> + if (isDeviceAwake()) { + return collapseShadeLockedOrShowPrimaryBouncer() + } } } return false @@ -92,16 +97,24 @@ constructor( (statusBarStateController.state != StatusBarState.SHADE) && statusBarKeyguardViewManager.shouldDismissOnMenuPressed() if (shouldUnlockOnMenuPressed) { - shadeController.animateCollapseShadeForced() - return true + return collapseShadeLockedOrShowPrimaryBouncer() } return false } - private fun dispatchSpaceEvent(): Boolean { - if (isDeviceAwake() && statusBarStateController.state != StatusBarState.SHADE) { - shadeController.animateCollapseShadeForced() - return true + private fun collapseShadeLockedOrShowPrimaryBouncer(): Boolean { + when (statusBarStateController.state) { + StatusBarState.SHADE -> return false + StatusBarState.SHADE_LOCKED -> { + shadeController.animateCollapseShadeForced() + return true + } + StatusBarState.KEYGUARD -> { + if (!statusBarKeyguardViewManager.primaryBouncerIsShowing()) { + statusBarKeyguardViewManager.showPrimaryBouncer(true) + return true + } + } } return false } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt index abc30efec716..c5a8375f5576 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt @@ -47,6 +47,7 @@ import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.VibratorHelper +import com.android.systemui.util.doOnEnd import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -402,6 +403,9 @@ object KeyguardBottomAreaViewBinder { KeyguardBottomAreaVibrations.ShakeAnimationDuration.inWholeMilliseconds shakeAnimator.interpolator = CycleInterpolator(KeyguardBottomAreaVibrations.ShakeAnimationCycles) + shakeAnimator.doOnEnd { + view.translationX = 0f + } shakeAnimator.start() vibratorHelper?.vibrate(KeyguardBottomAreaVibrations.Shake) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt index f0d118cbe20f..99025acef70d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt @@ -41,6 +41,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceViewMod import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.VibratorHelper +import com.android.systemui.util.doOnEnd import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine @@ -240,6 +241,9 @@ object KeyguardQuickAffordanceViewBinder { KeyguardBottomAreaVibrations.ShakeAnimationDuration.inWholeMilliseconds shakeAnimator.interpolator = CycleInterpolator(KeyguardBottomAreaVibrations.ShakeAnimationCycles) + shakeAnimator.doOnEnd { + view.translationX = 0f + } shakeAnimator.start() vibratorHelper?.vibrate(KeyguardBottomAreaVibrations.Shake) diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt index 72aea040ba05..2217509167ef 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt @@ -33,6 +33,8 @@ import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnail import com.android.systemui.mediaprojection.appselector.data.ShellRecentTaskListProvider import com.android.systemui.mediaprojection.appselector.view.MediaProjectionRecentsViewController import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider +import com.android.systemui.mediaprojection.appselector.view.WindowMetricsProvider +import com.android.systemui.mediaprojection.appselector.view.WindowMetricsProviderImpl import com.android.systemui.mediaprojection.devicepolicy.MediaProjectionDevicePolicyModule import com.android.systemui.mediaprojection.devicepolicy.PersonalProfile import com.android.systemui.mediaprojection.permission.MediaProjectionPermissionActivity @@ -106,6 +108,8 @@ interface MediaProjectionAppSelectorModule { impl: TaskPreviewSizeProvider ): DefaultLifecycleObserver + @Binds fun windowMetricsProvider(impl: WindowMetricsProviderImpl): WindowMetricsProvider + companion object { @Provides @MediaProjectionAppSelector diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt index 864d35af41b4..c829471f53f3 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt @@ -19,8 +19,6 @@ package com.android.systemui.mediaprojection.appselector.view import android.content.Context import android.content.res.Configuration import android.graphics.Rect -import android.view.WindowInsets.Type -import android.view.WindowManager import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorScope @@ -36,7 +34,7 @@ class TaskPreviewSizeProvider @Inject constructor( private val context: Context, - private val windowManager: WindowManager, + private val windowMetricsProvider: WindowMetricsProvider, private val configurationController: ConfigurationController, ) : CallbackController<TaskPreviewSizeListener>, ConfigurationListener, DefaultLifecycleObserver { @@ -62,17 +60,14 @@ constructor( } private fun calculateSize(): Rect { - val windowMetrics = windowManager.maximumWindowMetrics - val maximumWindowHeight = windowMetrics.bounds.height() - val width = windowMetrics.bounds.width() + val maxWindowBounds = windowMetricsProvider.maximumWindowBounds + val maximumWindowHeight = maxWindowBounds.height() + val width = maxWindowBounds.width() var height = maximumWindowHeight val isLargeScreen = isLargeScreen(context) if (isLargeScreen) { - val taskbarSize = - windowManager.currentWindowMetrics.windowInsets - .getInsets(Type.tappableElement()) - .bottom + val taskbarSize = windowMetricsProvider.currentWindowInsets.bottom height -= taskbarSize } diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProvider.kt new file mode 100644 index 000000000000..193292032868 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProvider.kt @@ -0,0 +1,30 @@ +package com.android.systemui.mediaprojection.appselector.view + +import android.graphics.Insets +import android.graphics.Rect +import android.view.WindowInsets +import android.view.WindowManager +import javax.inject.Inject + +/** Provides values related to window metrics. */ +interface WindowMetricsProvider { + + val maximumWindowBounds: Rect + + val currentWindowInsets: Insets +} + +class WindowMetricsProviderImpl +@Inject +constructor( + private val windowManager: WindowManager, +) : WindowMetricsProvider { + override val maximumWindowBounds: Rect + get() = windowManager.maximumWindowMetrics.bounds + + override val currentWindowInsets: Insets + get() = + windowManager.currentWindowMetrics.windowInsets.getInsets( + WindowInsets.Type.tappableElement() + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java index 2b56d0cf9f83..d08d0400f354 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java @@ -239,6 +239,8 @@ public class MediaProjectionPermissionActivity extends Activity protected void onDestroy() { super.onDestroy(); if (mDialog != null) { + mDialog.setOnDismissListener(null); + mDialog.setOnCancelListener(null); mDialog.dismiss(); } } diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java index 07846b56d784..3cdcb2c4f550 100644 --- a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java +++ b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java @@ -24,6 +24,8 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.shared.system.QuickStepContract; +import dalvik.annotation.optimization.NeverCompile; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -108,6 +110,7 @@ public class SysUiState implements Dumpable { } } + @NeverCompile @Override public void dump(PrintWriter pw, String[] args) { pw.println("SysUiState state:"); diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java index 564e984fbce2..2928cceb35aa 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java @@ -65,6 +65,8 @@ import com.android.systemui.util.settings.SecureSettings; import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.pip.Pip; +import dalvik.annotation.optimization.NeverCompile; + import java.io.PrintWriter; import java.util.Optional; @@ -476,6 +478,7 @@ public class NavigationBarControllerImpl implements return mNavigationBars.get(mDisplayTracker.getDefaultDisplayId()); } + @NeverCompile @Override public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { pw.println("mIsLargeScreen=" + mIsLargeScreen); diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index 4d6d95a05b1b..bc4f7f2513ce 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -584,7 +584,6 @@ public class NavigationBarView extends FrameLayout { if (!visible) { mTransitionListener.onBackAltCleared(); } - mRotationButtonController.getRotationButton().setCanShowRotationButton(!visible); } void setDisabledFlags(int disabledFlags, SysUiState sysUiState) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java index 202254bb323f..4aad6a069cbb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java @@ -72,6 +72,8 @@ import com.android.systemui.statusbar.policy.BrightnessMirrorController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.util.Utils; +import dalvik.annotation.optimization.NeverCompile; + import java.io.PrintWriter; import java.util.Arrays; import java.util.function.Consumer; @@ -934,6 +936,7 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl return mListeningAndVisibilityLifecycleOwner; } + @NeverCompile @Override public void dump(PrintWriter pw, String[] args) { IndentingPrintWriter indentingPw = new IndentingPrintWriter(pw, /* singleIndent= */ " "); 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 584456d79890..91b4d1778e1c 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 @@ -42,6 +42,7 @@ import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICA import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING +import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.distinctUntilChanged @@ -51,7 +52,6 @@ import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.launch -import javax.inject.Inject /** * Hooks up business logic that manipulates the state of the [SceneInteractor] for the system UI @@ -142,7 +142,7 @@ constructor( // When the device becomes unlocked in Lockscreen, go to Gone if // bypass is enabled. renderedScenes.contains(SceneKey.Lockscreen) -> - if (deviceEntryInteractor.isBypassEnabled()) { + if (deviceEntryInteractor.isBypassEnabled.value) { SceneKey.Gone to "device unlocked in Lockscreen scene with bypass" } else { @@ -179,36 +179,34 @@ constructor( } applicationScope.launch { - powerInteractor.isAsleep - .collect { isAsleep -> - if (isAsleep) { - switchToScene( - targetSceneKey = SceneKey.Lockscreen, - loggingReason = "device is starting to sleep", - ) - } else { - val authMethod = authenticationInteractor.getAuthenticationMethod() - val isUnlocked = deviceEntryInteractor.isUnlocked.value - when { - authMethod == AuthenticationMethodModel.None -> { - switchToScene( - targetSceneKey = SceneKey.Gone, - loggingReason = - "device is starting to wake up while auth method is" + - " none", - ) - } - authMethod.isSecure && isUnlocked -> { - switchToScene( - targetSceneKey = SceneKey.Gone, - loggingReason = - "device is starting to wake up while unlocked with a" + - " secure auth method", - ) - } + powerInteractor.isAsleep.collect { isAsleep -> + if (isAsleep) { + switchToScene( + targetSceneKey = SceneKey.Lockscreen, + loggingReason = "device is starting to sleep", + ) + } else { + val authMethod = authenticationInteractor.getAuthenticationMethod() + val isUnlocked = deviceEntryInteractor.isUnlocked.value + when { + authMethod == AuthenticationMethodModel.None -> { + switchToScene( + targetSceneKey = SceneKey.Gone, + loggingReason = + "device is starting to wake up while auth method is" + " none", + ) + } + authMethod.isSecure && isUnlocked -> { + switchToScene( + targetSceneKey = SceneKey.Gone, + loggingReason = + "device is starting to wake up while unlocked with a" + + " secure auth method", + ) } } } + } } } diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt index 4bc93a8f1ca5..2e45353634fe 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt @@ -61,12 +61,17 @@ sealed interface UserAction { data class Swipe( /** The direction of the swipe. */ val direction: Direction, + /** + * The edge from which the swipe originated or `null`, if the swipe didn't start close to an + * edge. + */ + val fromEdge: Edge? = null, /** The number of pointers that were used (for example, one or two fingers). */ val pointerCount: Int = 1, ) : UserAction /** The user has hit the back button or performed the back navigation gesture. */ - object Back : UserAction + data object Back : UserAction } /** Enumerates all known "cardinal" directions for user actions. */ @@ -76,3 +81,11 @@ enum class Direction { RIGHT, DOWN, } + +/** Enumerates all known edges from which a swipe can start. */ +enum class Edge { + LEFT, + TOP, + RIGHT, + BOTTOM, +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 2ef83dd42868..ba0cf08150f6 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -230,6 +230,8 @@ import com.android.systemui.util.Utils; import com.android.systemui.util.time.SystemClock; import com.android.wm.shell.animation.FlingAnimationUtils; +import dalvik.annotation.optimization.NeverCompile; + import kotlin.Unit; import java.io.PrintWriter; @@ -3379,6 +3381,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mBlockingExpansionForCurrentTouch = isTracking(); } + @NeverCompile @Override public void dump(PrintWriter pw, String[] args) { pw.println(TAG + ":"); diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 5414b3f30aa5..d05dfe2c11c1 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -48,7 +48,7 @@ import com.android.systemui.dock.DockManager; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; -import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor; +import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.shared.model.TransitionState; @@ -106,7 +106,7 @@ public class NotificationShadeWindowViewController implements Dumpable { private final NotificationInsetsController mNotificationInsetsController; private final boolean mIsTrackpadCommonEnabled; private final FeatureFlags mFeatureFlags; - private final KeyEventInteractor mKeyEventInteractor; + private final SysUIKeyEventHandler mSysUIKeyEventHandler; private final PrimaryBouncerInteractor mPrimaryBouncerInteractor; private final AlternateBouncerInteractor mAlternateBouncerInteractor; private GestureDetector mPulsingWakeupGestureHandler; @@ -185,7 +185,7 @@ public class NotificationShadeWindowViewController implements Dumpable { SystemClock clock, BouncerMessageInteractor bouncerMessageInteractor, BouncerLogger bouncerLogger, - KeyEventInteractor keyEventInteractor, + SysUIKeyEventHandler sysUIKeyEventHandler, PrimaryBouncerInteractor primaryBouncerInteractor, AlternateBouncerInteractor alternateBouncerInteractor) { mLockscreenShadeTransitionController = transitionController; @@ -214,7 +214,7 @@ public class NotificationShadeWindowViewController implements Dumpable { mNotificationInsetsController = notificationInsetsController; mIsTrackpadCommonEnabled = featureFlags.isEnabled(TRACKPAD_GESTURE_COMMON); mFeatureFlags = featureFlags; - mKeyEventInteractor = keyEventInteractor; + mSysUIKeyEventHandler = sysUIKeyEventHandler; mPrimaryBouncerInteractor = primaryBouncerInteractor; mAlternateBouncerInteractor = alternateBouncerInteractor; @@ -529,17 +529,17 @@ public class NotificationShadeWindowViewController implements Dumpable { @Override public boolean interceptMediaKey(KeyEvent event) { - return mKeyEventInteractor.interceptMediaKey(event); + return mSysUIKeyEventHandler.interceptMediaKey(event); } @Override public boolean dispatchKeyEventPreIme(KeyEvent event) { - return mKeyEventInteractor.dispatchKeyEventPreIme(event); + return mSysUIKeyEventHandler.dispatchKeyEventPreIme(event); } @Override public boolean dispatchKeyEvent(KeyEvent event) { - return mKeyEventInteractor.dispatchKeyEvent(event); + return mSysUIKeyEventHandler.dispatchKeyEvent(event); } }); diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java index 9b74ac4afed4..3bbb2cf83a83 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java @@ -105,6 +105,8 @@ import com.android.systemui.statusbar.policy.SplitShadeStateController; import com.android.systemui.util.LargeScreenUtils; import com.android.systemui.util.kotlin.JavaAdapter; +import dalvik.annotation.optimization.NeverCompile; + import dagger.Lazy; import java.io.PrintWriter; @@ -2015,6 +2017,7 @@ public class QuickSettingsController implements Dumpable { (int) ((y - getInitialTouchY()) / displayDensity), (int) (vel / displayDensity)); } + @NeverCompile @Override public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { pw.println(TAG + ":"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java index d24f9d8f476c..77b095802b00 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java @@ -18,6 +18,8 @@ package com.android.systemui.statusbar; import android.view.View; +import androidx.annotation.Nullable; + import com.android.app.animation.Interpolators; import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; @@ -113,7 +115,16 @@ public class CrossFadeHelper { fadeIn(view, ANIMATION_DURATION_LENGTH, 0); } + public static void fadeIn(final View view, Runnable endRunnable) { + fadeIn(view, ANIMATION_DURATION_LENGTH, /* delay= */ 0, endRunnable); + } + public static void fadeIn(final View view, long duration, int delay) { + fadeIn(view, duration, delay, /* endRunnable= */ null); + } + + public static void fadeIn(final View view, long duration, int delay, + @Nullable Runnable endRunnable) { view.animate().cancel(); if (view.getVisibility() == View.INVISIBLE) { view.setAlpha(0.0f); @@ -124,7 +135,7 @@ public class CrossFadeHelper { .setDuration(duration) .setStartDelay(delay) .setInterpolator(Interpolators.ALPHA_IN) - .withEndAction(null); + .withEndAction(endRunnable); if (view.hasOverlappingRendering() && view.getLayerType() != View.LAYER_TYPE_HARDWARE) { view.animate().withLayer(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index f616b91c4712..3a4ad0e79994 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -51,6 +51,7 @@ import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.animation.Interpolator; +import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import com.android.app.animation.Interpolators; @@ -959,12 +960,17 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi } public void setDozing(boolean dozing, boolean fade, long delay) { + setDozing(dozing, fade, delay, /* onChildCompleted= */ null); + } + + public void setDozing(boolean dozing, boolean fade, long delay, + @Nullable Runnable endRunnable) { mDozer.setDozing(f -> { mDozeAmount = f; updateDecorColor(); updateIconColor(); updateAllowAnimation(); - }, dozing, fade, delay, this); + }, dozing, fade, delay, this, endRunnable); } private void updateAllowAnimation() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java index 9db61c6b3ba2..fc84973c46bd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java @@ -83,6 +83,8 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceP import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.util.CarrierConfigTracker; +import dalvik.annotation.optimization.NeverCompile; + import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -1154,6 +1156,7 @@ public class NetworkControllerImpl extends BroadcastReceiver } /** */ + @NeverCompile public void dump(PrintWriter pw, String[] args) { pw.println("NetworkController state:"); pw.println(" mUserSetup=" + mUserSetup); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java index 167efc784ff5..dc0eb7b4aab3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java @@ -24,6 +24,8 @@ import android.graphics.ColorMatrixColorFilter; import android.view.View; import android.widget.ImageView; +import androidx.annotation.Nullable; + import com.android.app.animation.Interpolators; import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; @@ -81,6 +83,11 @@ public class NotificationDozeHelper { public void setDozing(Consumer<Float> listener, boolean dozing, boolean animate, long delay, View view) { + setDozing(listener, dozing, animate, delay, view, /* endRunnable= */ null); + } + + public void setDozing(Consumer<Float> listener, boolean dozing, + boolean animate, long delay, View view, @Nullable Runnable endRunnable) { if (animate) { startIntensityAnimation(a -> listener.accept((Float) a.getAnimatedValue()), dozing, delay, @@ -89,6 +96,9 @@ public class NotificationDozeHelper { @Override public void onAnimationEnd(Animator animation) { view.setTag(DOZE_ANIMATOR_TAG, null); + if (endRunnable != null) { + endRunnable.run(); + } } @Override @@ -102,6 +112,9 @@ public class NotificationDozeHelper { animator.cancel(); } listener.accept(dozing ? 1f : 0f); + if (endRunnable != null) { + endRunnable.run(); + } } } 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 733d774f8b80..8561869af352 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 @@ -53,6 +53,7 @@ import com.android.systemui.statusbar.notification.collection.render.GroupMember import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager; import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; +import com.android.systemui.statusbar.notification.data.NotificationDataLayerModule; import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository; import com.android.systemui.statusbar.notification.icon.ConversationIconManager; import com.android.systemui.statusbar.notification.icon.IconManager; @@ -95,6 +96,7 @@ import javax.inject.Provider; CoordinatorsModule.class, KeyguardNotificationVisibilityProviderModule.class, ShadeEventsModule.class, + NotificationDataLayerModule.class, NotifPipelineChoreographerModule.class, NotificationSectionHeadersModule.class, NotificationListViewModelModule.class, 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 new file mode 100644 index 000000000000..5435fb5449cd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt @@ -0,0 +1,22 @@ +/* + * 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 com.android.systemui.statusbar.notification.data + +import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardStateRepositoryModule +import dagger.Module + +@Module(includes = [NotificationsKeyguardStateRepositoryModule::class]) +interface NotificationDataLayerModule diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepository.kt new file mode 100644 index 000000000000..cf03d1c5addc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepository.kt @@ -0,0 +1,73 @@ +/* + * 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 com.android.systemui.statusbar.notification.data.repository + +import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator +import dagger.Binds +import dagger.Module +import javax.inject.Inject +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow + +/** View-states pertaining to notifications on the keyguard. */ +interface NotificationsKeyguardViewStateRepository { + /** Are notifications fully hidden from view? */ + val areNotificationsFullyHidden: Flow<Boolean> + + /** Is a pulse expansion occurring? */ + val isPulseExpanding: Flow<Boolean> +} + +@Module +interface NotificationsKeyguardStateRepositoryModule { + @Binds + fun bindImpl( + impl: NotificationsKeyguardViewStateRepositoryImpl + ): NotificationsKeyguardViewStateRepository +} + +@SysUISingleton +class NotificationsKeyguardViewStateRepositoryImpl +@Inject +constructor( + wakeUpCoordinator: NotificationWakeUpCoordinator, +) : NotificationsKeyguardViewStateRepository { + override val areNotificationsFullyHidden: Flow<Boolean> = conflatedCallbackFlow { + val listener = + object : NotificationWakeUpCoordinator.WakeUpListener { + override fun onFullyHiddenChanged(isFullyHidden: Boolean) { + trySend(isFullyHidden) + } + } + trySend(wakeUpCoordinator.notificationsFullyHidden) + wakeUpCoordinator.addListener(listener) + awaitClose { wakeUpCoordinator.removeListener(listener) } + } + + override val isPulseExpanding: Flow<Boolean> = conflatedCallbackFlow { + val listener = + object : NotificationWakeUpCoordinator.WakeUpListener { + override fun onPulseExpansionChanged(expandingChanged: Boolean) { + trySend(expandingChanged) + } + } + trySend(wakeUpCoordinator.isPulseExpanding()) + wakeUpCoordinator.addListener(listener) + awaitClose { wakeUpCoordinator.removeListener(listener) } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt new file mode 100644 index 000000000000..87b8e55dbd1a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt @@ -0,0 +1,33 @@ +/* + * 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 com.android.systemui.statusbar.notification.domain.interactor + +import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardViewStateRepository +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow + +/** Domain logic pertaining to notifications on the keyguard. */ +class NotificationsKeyguardInteractor +@Inject +constructor( + repository: NotificationsKeyguardViewStateRepository, +) { + /** Is a pulse expansion occurring? */ + val isPulseExpanding: Flow<Boolean> = repository.isPulseExpanding + + /** Are notifications fully hidden from view? */ + val areNotificationsFullyHidden: Flow<Boolean> = repository.areNotificationsFullyHidden +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java index 26db5f2bc095..e74b3fcdf050 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java @@ -11,10 +11,10 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ -package com.android.systemui.statusbar.notification.row; +package com.android.systemui.statusbar.notification.footer.ui.view; import static android.graphics.PorterDuff.Mode.SRC_ATOP; @@ -35,6 +35,8 @@ import androidx.annotation.NonNull; import com.android.settingslib.Utils; import com.android.systemui.res.R; +import com.android.systemui.statusbar.notification.row.FooterViewButton; +import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.ViewState; import com.android.systemui.util.DumpUtilsKt; @@ -93,6 +95,7 @@ public class FooterView extends StackScrollerDecorView { updateColors(); } + /** Show a message instead of the footer buttons. */ public void setFooterLabelVisible(boolean isVisible) { if (isVisible) { mManageButton.setVisibility(View.GONE); @@ -105,14 +108,22 @@ public class FooterView extends StackScrollerDecorView { } } + /** Set onClickListener for the manage/history button. */ public void setManageButtonClickListener(OnClickListener listener) { mManageButton.setOnClickListener(listener); } + /** Set onClickListener for the clear all (end) button. */ public void setClearAllButtonClickListener(OnClickListener listener) { mClearAllButton.setOnClickListener(listener); } + /** + * Whether the touch is outside the Clear all button. + * + * TODO(b/293167744): This is an artifact from the time when we could press underneath the + * shade to dismiss it. Check if it's safe to remove. + */ public boolean isOnEmptySpace(float touchX, float touchY) { return touchX < mContent.getX() || touchX > mContent.getX() + mContent.getWidth() @@ -120,6 +131,7 @@ public class FooterView extends StackScrollerDecorView { || touchY > mContent.getY() + mContent.getHeight(); } + /** Show "History" instead of "Manage" on the start button. */ public void showHistory(boolean showHistory) { if (mShowHistory == showHistory) { return; @@ -141,6 +153,7 @@ public class FooterView extends StackScrollerDecorView { .setCompoundDrawablesRelative(mSeenNotifsFilteredIcon, null, null, null); } + /** Whether the start button shows "History" (true) or "Manage" (false). */ public boolean isHistoryShown() { return mShowHistory; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt index a77e67b6908d..805a4dba111f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt @@ -26,26 +26,21 @@ import android.widget.FrameLayout import androidx.annotation.ColorInt import androidx.annotation.VisibleForTesting import androidx.collection.ArrayMap -import com.android.app.animation.Interpolators import com.android.internal.statusbar.StatusBarIcon import com.android.internal.util.ContrastColorUtil import com.android.settingslib.Utils import com.android.systemui.dagger.SysUISingleton import com.android.systemui.demomode.DemoMode import com.android.systemui.demomode.DemoModeController -import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags -import com.android.systemui.flags.Flags.NEW_AOD_TRANSITION import com.android.systemui.flags.ViewRefactorFlag import com.android.systemui.plugins.DarkIconDispatcher -import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.res.R -import com.android.systemui.statusbar.CrossFadeHelper import com.android.systemui.statusbar.NotificationListener import com.android.systemui.statusbar.NotificationMediaManager import com.android.systemui.statusbar.NotificationShelfController import com.android.systemui.statusbar.StatusBarIconView -import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.notification.NotificationUtils import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator import com.android.systemui.statusbar.notification.collection.ListEntry @@ -60,6 +55,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.NotificationIconAreaController import com.android.systemui.statusbar.phone.NotificationIconContainer import com.android.systemui.statusbar.phone.ScreenOffAnimationController +import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.window.StatusBarWindowController import com.android.wm.shell.bubbles.Bubbles import java.util.Optional @@ -79,9 +75,9 @@ class NotificationIconAreaControllerViewBinderWrapperImpl @Inject constructor( private val context: Context, - private val statusBarStateController: StatusBarStateController, private val wakeUpCoordinator: NotificationWakeUpCoordinator, private val bypassController: KeyguardBypassController, + private val configurationController: ConfigurationController, private val mediaManager: NotificationMediaManager, notificationListener: NotificationListener, private val dozeParameters: DozeParameters, @@ -89,7 +85,7 @@ constructor( private val bubblesOptional: Optional<Bubbles>, demoModeController: DemoModeController, darkIconDispatcher: DarkIconDispatcher, - private val featureFlags: FeatureFlags, + private val featureFlags: FeatureFlagsClassic, private val statusBarWindowController: StatusBarWindowController, private val screenOffAnimationController: ScreenOffAnimationController, private val shelfIconsViewModel: NotificationIconContainerShelfViewModel, @@ -98,14 +94,12 @@ constructor( ) : NotificationIconAreaController, DarkIconDispatcher.DarkReceiver, - StatusBarStateController.StateListener, NotificationWakeUpCoordinator.WakeUpListener, DemoMode { private val contrastColorUtil: ContrastColorUtil = ContrastColorUtil.getInstance(context) private val updateStatusBarIcons = Runnable { updateStatusBarIcons() } private val shelfRefactor = ViewRefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR) - private val statusViewMigrated = featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW) private val tintAreas = ArrayList<Rect>() private var iconSize = 0 @@ -119,7 +113,6 @@ constructor( private var aodBindJob: DisposableHandle? = null private var aodIconAppearTranslation = 0 private var aodIconTint = 0 - private var aodIconsVisible = false private var showLowPriority = true @VisibleForTesting @@ -132,7 +125,6 @@ constructor( } init { - statusBarStateController.addCallback(this) wakeUpCoordinator.addListener(this) demoModeController.addCallback(this) notificationListener.addNotificationSettingsListener(settingsListener) @@ -160,8 +152,11 @@ constructor( NotificationIconContainerViewBinder.bind( aodIcons, aodIconsViewModel, + configurationController, + dozeParameters, + featureFlags, + screenOffAnimationController, ) - updateAodIconsVisibility(animate = false, forceUpdate = changed) if (changed) { updateAodNotificationIcons() } @@ -176,6 +171,10 @@ constructor( NotificationIconContainerViewBinder.bind( icons, shelfIconsViewModel, + configurationController, + dozeParameters, + featureFlags, + screenOffAnimationController, ) shelfIcons = icons } @@ -249,20 +248,8 @@ constructor( notificationIcons!!.setIsolatedIconLocation(iconDrawingRect, requireStateUpdate) } - override fun onDozingChanged(isDozing: Boolean) { - if (aodIcons == null) { - return - } - val animate = (dozeParameters.alwaysOn && !dozeParameters.displayNeedsBlanking) - aodIcons!!.setDozing(isDozing, animate, 0) - } - override fun setAnimationsEnabled(enabled: Boolean) = unsupported - override fun onStateChanged(newState: Int) { - updateAodIconsVisibility(animate = false, forceUpdate = false) - } - override fun onThemeChanged() { reloadAodColor() updateAodIconColors() @@ -272,53 +259,11 @@ constructor( return if (aodIcons == null) 0 else aodIcons!!.height } - @VisibleForTesting - fun appearAodIcons() { - if (aodIcons == null) { - return - } - if (screenOffAnimationController.shouldAnimateAodIcons()) { - if (!statusViewMigrated) { - aodIcons!!.translationY = -aodIconAppearTranslation.toFloat() - } - aodIcons!!.alpha = 0f - animateInAodIconTranslation() - aodIcons!! - .animate() - .alpha(1f) - .setInterpolator(Interpolators.LINEAR) - .setDuration(AOD_ICONS_APPEAR_DURATION) - .start() - } else { - aodIcons!!.alpha = 1.0f - if (!statusViewMigrated) { - aodIcons!!.translationY = 0f - } - } - } - override fun onFullyHiddenChanged(isFullyHidden: Boolean) { - var animate = true - if (!bypassController.bypassEnabled) { - animate = dozeParameters.alwaysOn && !dozeParameters.displayNeedsBlanking - if (!featureFlags.isEnabled(NEW_AOD_TRANSITION)) { - // We only want the appear animations to happen when the notifications get fully - // hidden, - // since otherwise the unhide animation overlaps - animate = animate and isFullyHidden - } - } - updateAodIconsVisibility(animate, false /* force */) updateAodNotificationIcons() updateAodIconColors() } - override fun onPulseExpansionChanged(expandingChanged: Boolean) { - if (expandingChanged) { - updateAodIconsVisibility(animate = true, forceUpdate = false) - } - } - override fun demoCommands(): List<String> { val commands = ArrayList<String>() commands.add(DemoMode.COMMAND_NOTIFICATIONS) @@ -352,6 +297,10 @@ constructor( NotificationIconContainerViewBinder.bind( notificationIcons!!, statusBarIconsViewModel, + configurationController, + dozeParameters, + featureFlags, + screenOffAnimationController, ) } @@ -602,17 +551,6 @@ constructor( v.setDecorColor(tint) } - private fun animateInAodIconTranslation() { - if (!statusViewMigrated) { - aodIcons!! - .animate() - .setInterpolator(Interpolators.DECELERATE_QUINT) - .translationY(0f) - .setDuration(AOD_ICONS_APPEAR_DURATION) - .start() - } - } - private fun reloadAodColor() { aodIconTint = Utils.getColorAttrDefaultColor( @@ -635,69 +573,7 @@ constructor( } } - private fun updateAodIconsVisibility(animate: Boolean, forceUpdate: Boolean) { - if (aodIcons == null) { - return - } - var visible = (bypassController.bypassEnabled || wakeUpCoordinator.notificationsFullyHidden) - - // Hide the AOD icons if we're not in the KEYGUARD state unless the screen off animation is - // playing, in which case we want them to be visible since we're animating in the AOD UI and - // will be switching to KEYGUARD shortly. - if ( - statusBarStateController.state != StatusBarState.KEYGUARD && - !screenOffAnimationController.shouldShowAodIconsWhenShade() - ) { - visible = false - } - if (visible && wakeUpCoordinator.isPulseExpanding() && !bypassController.bypassEnabled) { - visible = false - } - if (aodIconsVisible != visible || forceUpdate) { - aodIconsVisible = visible - aodIcons!!.animate().cancel() - if (animate) { - if (featureFlags.isEnabled(NEW_AOD_TRANSITION)) { - // Let's make sure the icon are translated to 0, since we cancelled it above - animateInAodIconTranslation() - if (aodIconsVisible) { - CrossFadeHelper.fadeIn(aodIcons) - } else { - CrossFadeHelper.fadeOut(aodIcons) - } - } else { - val wasFullyInvisible = aodIcons!!.visibility != View.VISIBLE - if (aodIconsVisible) { - if (wasFullyInvisible) { - // No fading here, let's just appear the icons instead! - aodIcons!!.visibility = View.VISIBLE - aodIcons!!.alpha = 1.0f - appearAodIcons() - } else { - // Let's make sure the icon are translated to 0, since we cancelled it - // above - animateInAodIconTranslation() - // We were fading out, let's fade in instead - CrossFadeHelper.fadeIn(aodIcons) - } - } else { - // Let's make sure the icon are translated to 0, since we cancelled it above - animateInAodIconTranslation() - CrossFadeHelper.fadeOut(aodIcons) - } - } - } else { - aodIcons!!.alpha = 1.0f - if (!statusViewMigrated) { - aodIcons!!.translationY = 0f - } - aodIcons!!.visibility = if (visible) View.VISIBLE else View.INVISIBLE - } - } - } - companion object { - private const val AOD_ICONS_APPEAR_DURATION: Long = 200 @ColorInt private val DEFAULT_AOD_ICON_COLOR = -0x1 val unsupported: Nothing diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt index f8ff3e393033..0d2f00aa3627 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt @@ -15,12 +15,27 @@ */ package com.android.systemui.statusbar.notification.icon.ui.viewbinder +import android.content.res.Resources +import android.view.View +import androidx.annotation.DimenRes import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle +import com.android.app.animation.Interpolators +import com.android.systemui.flags.FeatureFlagsClassic +import com.android.systemui.flags.Flags import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.res.R +import com.android.systemui.statusbar.CrossFadeHelper import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel +import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.phone.NotificationIconContainer +import com.android.systemui.statusbar.phone.ScreenOffAnimationController +import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.onDensityOrFontScaleChanged +import com.android.systemui.util.kotlin.stateFlow +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DisposableHandle +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch /** Binds a [NotificationIconContainer] to its [view model][NotificationIconContainerViewModel]. */ @@ -28,11 +43,144 @@ object NotificationIconContainerViewBinder { fun bind( view: NotificationIconContainer, viewModel: NotificationIconContainerViewModel, + configurationController: ConfigurationController, + dozeParameters: DozeParameters, + featureFlags: FeatureFlagsClassic, + screenOffAnimationController: ScreenOffAnimationController, ): DisposableHandle { return view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { launch { viewModel.animationsEnabled.collect(view::setAnimationsEnabled) } + launch { + viewModel.isDozing.collect { (isDozing, animate) -> + val animateIfNotBlanking = animate && !dozeParameters.displayNeedsBlanking + view.setDozing(isDozing, animateIfNotBlanking, /* delay= */ 0) { + viewModel.completeDozeAnimation() + } + } + } + // TODO(278765923): this should live where AOD is bound, not inside of the NIC + // view-binder + launch { + val iconAppearTranslation = + view.resources.getConfigAwareDimensionPixelSize( + this, + configurationController, + R.dimen.shelf_appear_translation, + ) + bindVisibility( + viewModel, + view, + featureFlags, + screenOffAnimationController, + iconAppearTranslation, + ) { + viewModel.completeVisibilityAnimation() + } + } } } } + private suspend fun bindVisibility( + viewModel: NotificationIconContainerViewModel, + view: NotificationIconContainer, + featureFlags: FeatureFlagsClassic, + screenOffAnimationController: ScreenOffAnimationController, + iconAppearTranslation: StateFlow<Int>, + onAnimationEnd: () -> Unit, + ) { + val statusViewMigrated = featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW) + viewModel.isVisible.collect { (isVisible, animate) -> + view.animate().cancel() + when { + !animate -> { + view.alpha = 1f + if (!statusViewMigrated) { + view.translationY = 0f + } + view.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE + } + featureFlags.isEnabled(Flags.NEW_AOD_TRANSITION) -> { + animateInIconTranslation(view, statusViewMigrated) + if (isVisible) { + CrossFadeHelper.fadeIn(view, onAnimationEnd) + } else { + CrossFadeHelper.fadeOut(view, onAnimationEnd) + } + } + !isVisible -> { + // Let's make sure the icon are translated to 0, since we cancelled it above + animateInIconTranslation(view, statusViewMigrated) + CrossFadeHelper.fadeOut(view, onAnimationEnd) + } + view.visibility != View.VISIBLE -> { + // No fading here, let's just appear the icons instead! + view.visibility = View.VISIBLE + view.alpha = 1f + appearIcons( + view, + animate = screenOffAnimationController.shouldAnimateAodIcons(), + iconAppearTranslation.value, + statusViewMigrated, + ) + onAnimationEnd() + } + else -> { + // Let's make sure the icons are translated to 0, since we cancelled it above + animateInIconTranslation(view, statusViewMigrated) + // We were fading out, let's fade in instead + CrossFadeHelper.fadeIn(view, onAnimationEnd) + } + } + } + } + + private fun appearIcons( + view: View, + animate: Boolean, + iconAppearTranslation: Int, + statusViewMigrated: Boolean, + ) { + if (animate) { + if (!statusViewMigrated) { + view.translationY = -iconAppearTranslation.toFloat() + } + view.alpha = 0f + animateInIconTranslation(view, statusViewMigrated) + view + .animate() + .alpha(1f) + .setInterpolator(Interpolators.LINEAR) + .setDuration(AOD_ICONS_APPEAR_DURATION) + .start() + } else { + view.alpha = 1.0f + if (!statusViewMigrated) { + view.translationY = 0f + } + } + } + + private fun animateInIconTranslation(view: View, statusViewMigrated: Boolean) { + if (!statusViewMigrated) { + view + .animate() + .setInterpolator(Interpolators.DECELERATE_QUINT) + .translationY(0f) + .setDuration(AOD_ICONS_APPEAR_DURATION) + .start() + } + } + + private const val AOD_ICONS_APPEAR_DURATION: Long = 200 } + +fun Resources.getConfigAwareDimensionPixelSize( + scope: CoroutineScope, + configurationController: ConfigurationController, + @DimenRes id: Int, +): StateFlow<Int> = + scope.stateFlow( + changedSignals = configurationController.onDensityOrFontScaleChanged, + getValue = { getDimensionPixelSize(id) } + ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt index 90507fc82a79..3289a3ce5574 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt @@ -15,19 +15,48 @@ */ package com.android.systemui.statusbar.notification.icon.ui.viewmodel +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor +import com.android.systemui.flags.FeatureFlagsClassic +import com.android.systemui.flags.Flags 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.TransitionStep import com.android.systemui.shade.domain.interactor.ShadeInteractor +import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor +import com.android.systemui.statusbar.phone.DozeParameters +import com.android.systemui.statusbar.phone.ScreenOffAnimationController +import com.android.systemui.util.kotlin.pairwise +import com.android.systemui.util.kotlin.sample +import com.android.systemui.util.ui.AnimatableEvent +import com.android.systemui.util.ui.AnimatedValue +import com.android.systemui.util.ui.toAnimatedValueFlow import javax.inject.Inject import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map /** View-model for the row of notification icons displayed on the always-on display. */ +@SysUISingleton class NotificationIconContainerAlwaysOnDisplayViewModel @Inject constructor( + private val deviceEntryInteractor: DeviceEntryInteractor, + private val dozeParameters: DozeParameters, + private val featureFlags: FeatureFlagsClassic, keyguardInteractor: KeyguardInteractor, + keyguardTransitionInteractor: KeyguardTransitionInteractor, + private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor, + screenOffAnimationController: ScreenOffAnimationController, shadeInteractor: ShadeInteractor, ) : NotificationIconContainerViewModel { + + private val onDozeAnimationComplete = MutableSharedFlow<Unit>(extraBufferCapacity = 1) + private val onVisAnimationComplete = MutableSharedFlow<Unit>(extraBufferCapacity = 1) + override val animationsEnabled: Flow<Boolean> = combine( shadeInteractor.isShadeTouchable, @@ -35,4 +64,97 @@ constructor( ) { panelTouchesEnabled, isKeyguardVisible -> panelTouchesEnabled && isKeyguardVisible } + + override val isDozing: Flow<AnimatedValue<Boolean>> = + keyguardTransitionInteractor.startedKeyguardTransitionStep + // Determine if we're dozing based on the most recent transition + .map { step: TransitionStep -> + val isDozing = step.to == KeyguardState.AOD || step.to == KeyguardState.DOZING + isDozing to step + } + // Only emit changes based on whether we've started or stopped dozing + .distinctUntilChanged { (wasDozing, _), (isDozing, _) -> wasDozing != isDozing } + // Determine whether we need to animate + .map { (isDozing, step) -> + val animate = step.to == KeyguardState.AOD || step.from == KeyguardState.AOD + AnimatableEvent(isDozing, animate) + } + .distinctUntilChanged() + .toAnimatedValueFlow(completionEvents = onDozeAnimationComplete) + + override val isVisible: Flow<AnimatedValue<Boolean>> = + combine( + keyguardTransitionInteractor.finishedKeyguardState.map { it != KeyguardState.GONE }, + deviceEntryInteractor.isBypassEnabled, + areNotifsFullyHiddenAnimated(), + isPulseExpandingAnimated(), + ) { + onKeyguard: Boolean, + bypassEnabled: Boolean, + (notifsFullyHidden: Boolean, isAnimatingHide: Boolean), + (pulseExpanding: Boolean, isAnimatingPulse: Boolean), + -> + val isAnimating = isAnimatingHide || isAnimatingPulse + when { + // Hide the AOD icons if we're not in the KEYGUARD state unless the screen off + // animation is playing, in which case we want them to be visible if we're + // animating in the AOD UI and will be switching to KEYGUARD shortly. + !onKeyguard && !screenOffAnimationController.shouldShowAodIconsWhenShade() -> + AnimatedValue(false, isAnimating = false) + // If we're bypassing, then we're visible + bypassEnabled -> AnimatedValue(true, isAnimating) + // If we are pulsing (and not bypassing), then we are hidden + pulseExpanding -> AnimatedValue(false, isAnimating) + // If notifs are fully gone, then we're visible + notifsFullyHidden -> AnimatedValue(true, isAnimating) + // Otherwise, we're hidden + else -> AnimatedValue(false, isAnimating) + } + } + .distinctUntilChanged() + + override fun completeDozeAnimation() { + onDozeAnimationComplete.tryEmit(Unit) + } + + override fun completeVisibilityAnimation() { + onVisAnimationComplete.tryEmit(Unit) + } + + /** Is there an expanded pulse, are we animating in response? */ + private fun isPulseExpandingAnimated(): Flow<AnimatedValue<Boolean>> { + return notificationsKeyguardInteractor.isPulseExpanding + .pairwise(initialValue = null) + // If pulsing changes, start animating, unless it's the first emission + .map { (prev, expanding) -> + AnimatableEvent(expanding!!, startAnimating = prev != null) + } + .toAnimatedValueFlow(completionEvents = onVisAnimationComplete) + } + + /** Are notifications completely hidden from view, are we animating in response? */ + private fun areNotifsFullyHiddenAnimated(): Flow<AnimatedValue<Boolean>> { + return notificationsKeyguardInteractor.areNotificationsFullyHidden + .pairwise(initialValue = null) + .sample(deviceEntryInteractor.isBypassEnabled) { (prev, fullyHidden), bypassEnabled -> + val animate = + when { + // Don't animate for the first value + prev == null -> false + // Always animate if bypass is enabled. + bypassEnabled -> true + // If we're not bypassing and we're not going to AOD, then we're not + // animating. + !dozeParameters.alwaysOn -> false + // Don't animate when going to AOD if the display needs blanking. + dozeParameters.displayNeedsBlanking -> false + // We only want the appear animations to happen when the notifications + // get fully hidden, since otherwise the un-hide animation overlaps. + featureFlags.isEnabled(Flags.NEW_AOD_TRANSITION) -> true + else -> fullyHidden!! + } + AnimatableEvent(fullyHidden!!, animate) + } + .toAnimatedValueFlow(completionEvents = onVisAnimationComplete) + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt index 49f262de8f4a..c44a2b60142c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt @@ -15,12 +15,18 @@ */ package com.android.systemui.statusbar.notification.icon.ui.viewmodel +import com.android.systemui.util.ui.AnimatedValue import javax.inject.Inject import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flowOf /** View-model for the overflow row of notification icons displayed in the notification shade. */ class NotificationIconContainerShelfViewModel @Inject constructor() : NotificationIconContainerViewModel { override val animationsEnabled: Flow<Boolean> = flowOf(true) + override val isDozing: Flow<AnimatedValue<Boolean>> = emptyFlow() + override val isVisible: Flow<AnimatedValue<Boolean>> = emptyFlow() + override fun completeDozeAnimation() {} + override fun completeVisibilityAnimation() {} } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt index ee57b780b8c3..035687a4a91b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt @@ -17,9 +17,11 @@ package com.android.systemui.statusbar.notification.icon.ui.viewmodel import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractor +import com.android.systemui.util.ui.AnimatedValue import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.emptyFlow /** View-model for the row of notification icons displayed in the status bar, */ class NotificationIconContainerStatusBarViewModel @@ -35,4 +37,9 @@ constructor( ) { panelTouchesEnabled, isKeyguardShowing -> panelTouchesEnabled && !isKeyguardShowing } + + override val isDozing: Flow<AnimatedValue<Boolean>> = emptyFlow() + override val isVisible: Flow<AnimatedValue<Boolean>> = emptyFlow() + override fun completeDozeAnimation() {} + override fun completeVisibilityAnimation() {} } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt index 6f8ce4b1db4b..65eb22075ec7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt @@ -15,6 +15,7 @@ */ package com.android.systemui.statusbar.notification.icon.ui.viewmodel +import com.android.systemui.util.ui.AnimatedValue import kotlinx.coroutines.flow.Flow /** @@ -24,4 +25,22 @@ import kotlinx.coroutines.flow.Flow interface NotificationIconContainerViewModel { /** Are changes to the icon container animated? */ val animationsEnabled: Flow<Boolean> + + /** Should icons be rendered in "dozing" mode? */ + val isDozing: Flow<AnimatedValue<Boolean>> + + /** Is the icon container visible? */ + val isVisible: Flow<AnimatedValue<Boolean>> + + /** + * Signal completion of the [isDozing] animation; if [isDozing]'s [AnimatedValue.isAnimating] + * property was `true`, calling this method will update it to `false. + */ + fun completeDozeAnimation() + + /** + * Signal completion of the [isVisible] animation; if [isVisible]'s [AnimatedValue.isAnimating] + * property was `true`, calling this method will update it to `false. + */ + fun completeVisibilityAnimation() } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryDumper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryDumper.kt index 197ae1a77198..dc9028d94312 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryDumper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryDumper.kt @@ -25,6 +25,7 @@ import com.android.systemui.dump.DumpManager import com.android.systemui.dump.DumpsysTableLogger import com.android.systemui.dump.Row import com.android.systemui.statusbar.notification.collection.NotifPipeline +import dalvik.annotation.optimization.NeverCompile import java.io.PrintWriter import javax.inject.Inject @@ -39,6 +40,7 @@ constructor(val dumpManager: DumpManager, val notificationPipeline: NotifPipelin Log.i("NotificationMemory", "Registered dumpable.") } + @NeverCompile override fun dump(pw: PrintWriter, args: Array<out String>) { val memoryUse = NotificationMemoryMeter.notificationMemoryUse(notificationPipeline.allNotifs) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java index 42c80ed22717..40897dae4c44 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java @@ -42,9 +42,8 @@ import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.statusbar.IStatusBarService; -import com.android.systemui.Dependency; -import com.android.systemui.res.R; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; +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.util.Compile; @@ -76,7 +75,9 @@ public class FeedbackInfo extends LinearLayout implements NotificationGuts.GutsC final StatusBarNotification sbn, final NotificationEntry entry, final ExpandableNotificationRow row, - final AssistantFeedbackController controller) { + final AssistantFeedbackController controller, + final IStatusBarService statusBarService, + final NotificationGutsManager notificationGutsManager) { mPkg = sbn.getPackageName(); mPm = pm; mEntry = entry; @@ -84,8 +85,8 @@ public class FeedbackInfo extends LinearLayout implements NotificationGuts.GutsC mRanking = entry.getRanking(); mFeedbackController = controller; mAppName = mPkg; - mStatusBarService = Dependency.get(IStatusBarService.class); - mNotificationGutsManager = Dependency.get(NotificationGutsManager.class); + mStatusBarService = statusBarService; + mNotificationGutsManager = notificationGutsManager; bindHeader(); bindPrompt(); 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 dc318a392ed5..9e9116bd70e7 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 @@ -44,6 +44,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto; +import com.android.internal.statusbar.IStatusBarService; import com.android.settingslib.notification.ConversationIconFactory; import com.android.systemui.CoreStartable; import com.android.systemui.dagger.SysUISingleton; @@ -99,6 +100,7 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta // Dependencies: private final NotificationLockscreenUserManager mLockscreenUserManager; private final StatusBarStateController mStatusBarStateController; + private final IStatusBarService mStatusBarService; private final DeviceProvisionedController mDeviceProvisionedController; private final AssistantFeedbackController mAssistantFeedbackController; @@ -152,6 +154,7 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor, NotificationLockscreenUserManager notificationLockscreenUserManager, StatusBarStateController statusBarStateController, + IStatusBarService statusBarService, DeviceProvisionedController deviceProvisionedController, MetricsLogger metricsLogger, HeadsUpManager headsUpManager, @@ -177,6 +180,7 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor; mLockscreenUserManager = notificationLockscreenUserManager; mStatusBarStateController = statusBarStateController; + mStatusBarService = statusBarService; mDeviceProvisionedController = deviceProvisionedController; mMetricsLogger = metricsLogger; mHeadsUpManager = headsUpManager; @@ -358,7 +362,8 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta PackageManager pmUser = CentralSurfaces.getPackageManagerForUser(mContext, userHandle.getIdentifier()); - feedbackInfo.bindGuts(pmUser, sbn, row.getEntry(), row, mAssistantFeedbackController); + feedbackInfo.bindGuts(pmUser, sbn, row.getEntry(), row, mAssistantFeedbackController, + mStatusBarService, this); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java index 0c686be0406d..e200b901e815 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java @@ -167,7 +167,7 @@ public abstract class StackScrollerDecorView extends ExpandableView { } @VisibleForTesting - boolean isSecondaryVisible() { + public boolean isSecondaryVisible() { return mIsSecondaryVisible; } @@ -179,7 +179,8 @@ public abstract class StackScrollerDecorView extends ExpandableView { return mIsVisible; } - void setDuration(int duration) { + @VisibleForTesting + public void setDuration(int duration) { mDuration = duration; } 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 78d75582817b..10b1bcda27db 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 @@ -86,12 +86,12 @@ import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.ExpandHelper; -import com.android.systemui.res.R; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.flags.ViewRefactorFlag; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; +import com.android.systemui.res.R; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.TouchLogger; import com.android.systemui.statusbar.CommandQueue; @@ -106,12 +106,12 @@ import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; +import com.android.systemui.statusbar.notification.footer.ui.view.FooterView; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; -import com.android.systemui.statusbar.notification.row.FooterView; import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; import com.android.systemui.statusbar.phone.HeadsUpTouchHelper; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 8ca18521de63..80f98a68b4f4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -27,16 +27,16 @@ import android.view.ViewGroup; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.SystemBarUtils; import com.android.keyguard.BouncerPanelExpansionCalculator; -import com.android.systemui.res.R; import com.android.systemui.animation.ShadeInterpolation; +import com.android.systemui.res.R; import com.android.systemui.shade.transition.LargeScreenShadeInterpolator; import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.notification.SourceType; +import com.android.systemui.statusbar.notification.footer.ui.view.FooterView; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; -import com.android.systemui.statusbar.notification.row.FooterView; import java.util.ArrayList; import java.util.List; 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 6e6318e780dc..f380ce53b950 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -239,6 +239,8 @@ import com.android.wm.shell.startingsurface.StartingSurface; import dagger.Lazy; +import dalvik.annotation.optimization.NeverCompile; + import java.io.PrintWriter; import java.io.StringWriter; import java.util.List; @@ -1763,6 +1765,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } } + @NeverCompile @Override public void dump(PrintWriter pwOriginal, String[] args) { IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index 7cbaf63bc6db..b15c0fdd5a4c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -33,6 +33,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.animation.Interpolator; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.collection.ArrayMap; @@ -624,12 +625,32 @@ public class NotificationIconContainer extends ViewGroup { } public void setDozing(boolean dozing, boolean fade, long delay) { + setDozing(dozing, fade, delay, /* endRunnable= */ null); + } + + public void setDozing(boolean dozing, boolean fade, long delay, + @Nullable Runnable endRunnable) { mDozing = dozing; mDisallowNextAnimation |= !fade; - for (int i = 0; i < getChildCount(); i++) { + final int childCount = getChildCount(); + // Track all the child invocations of setDozing, invoking the top-level endRunnable once + // they have all completed. + final Runnable onChildCompleted = endRunnable == null ? null : new Runnable() { + private int mPendingCallbacks = childCount; + + @Override + public void run() { + if (--mPendingCallbacks == 0) { + endRunnable.run(); + } + } + }; + for (int i = 0; i < childCount; i++) { View view = getChildAt(i); if (view instanceof StatusBarIconView) { - ((StatusBarIconView) view).setDozing(dozing, fade, delay); + ((StatusBarIconView) view).setDozing(dozing, fade, delay, onChildCompleted); + } else if (onChildCompleted != null) { + onChildCompleted.run(); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt new file mode 100644 index 000000000000..21acfb41f10c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt @@ -0,0 +1,36 @@ +/* + * 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 com.android.systemui.statusbar.policy + +import com.android.systemui.common.coroutine.ConflatedCallbackFlow +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow + +/** + * A [Flow] that emits whenever screen density or font scale has changed. + * + * @see ConfigurationController.ConfigurationListener.onDensityOrFontScaleChanged + */ +val ConfigurationController.onDensityOrFontScaleChanged: Flow<Unit> + get() = + ConflatedCallbackFlow.conflatedCallbackFlow { + val listener = + object : ConfigurationController.ConfigurationListener { + override fun onDensityOrFontScaleChanged() { + trySend(Unit) + } + } + addCallback(listener) + awaitClose { removeCallback(listener) } + } diff --git a/packages/SystemUI/src/com/android/systemui/util/ReferenceExt.kt b/packages/SystemUI/src/com/android/systemui/util/ReferenceExt.kt new file mode 100644 index 000000000000..ac04d31041b6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/ReferenceExt.kt @@ -0,0 +1,50 @@ +package com.android.systemui.util + +import java.lang.ref.SoftReference +import java.lang.ref.WeakReference +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +/** + * Creates a Kotlin idiomatic weak reference. + * + * Usage: + * ``` + * var weakReferenceObj: Object? by weakReference(null) + * weakReferenceObj = Object() + * ``` + */ +fun <T> weakReference(obj: T? = null): ReadWriteProperty<Any?, T?> { + return object : ReadWriteProperty<Any?, T?> { + var weakRef = WeakReference<T?>(obj) + override fun getValue(thisRef: Any?, property: KProperty<*>): T? { + return weakRef.get() + } + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { + weakRef = WeakReference(value) + } + } +} + +/** + * Creates a Kotlin idiomatic soft reference. + * + * Usage: + * ``` + * var softReferenceObj: Object? by softReference(null) + * softReferenceObj = Object() + * ``` + */ +fun <T> softReference(obj: T? = null): ReadWriteProperty<Any?, T?> { + return object : ReadWriteProperty<Any?, T?> { + var softRef = SoftReference<T?>(obj) + override fun getValue(thisRef: Any?, property: KProperty<*>): T? { + return softRef.get() + } + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { + softRef = SoftReference(value) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt index 47d505ea36d5..83ff78980880 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt @@ -18,19 +18,24 @@ package com.android.systemui.util.kotlin import com.android.systemui.util.time.SystemClock import com.android.systemui.util.time.SystemClockImpl -import kotlinx.coroutines.CoroutineStart import java.util.concurrent.atomic.AtomicReference +import kotlin.math.max +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import kotlin.math.max /** * Returns a new [Flow] that combines the two most recent emissions from [this] using [transform]. @@ -44,8 +49,7 @@ fun <T, R> Flow<T>.pairwiseBy(transform: suspend (old: T, new: T) -> R): Flow<R> var previousValue: Any? = noVal collect { newVal -> if (previousValue != noVal) { - @Suppress("UNCHECKED_CAST") - emit(transform(previousValue as T, newVal)) + @Suppress("UNCHECKED_CAST") emit(transform(previousValue as T, newVal)) } previousValue = newVal } @@ -60,13 +64,11 @@ fun <T, R> Flow<T>.pairwiseBy(transform: suspend (old: T, new: T) -> R): Flow<R> fun <T, R> Flow<T>.pairwiseBy( initialValue: T, transform: suspend (previousValue: T, newValue: T) -> R, -): Flow<R> = - onStart { emit(initialValue) }.pairwiseBy(transform) +): Flow<R> = onStart { emit(initialValue) }.pairwiseBy(transform) /** * Returns a new [Flow] that combines the two most recent emissions from [this] using [transform]. * - * * The output of [getInitialValue] will be used as the "old" value for the first emission. As * opposed to the initial value in the above [pairwiseBy], [getInitialValue] can do some work before * returning the initial value. @@ -76,8 +78,7 @@ fun <T, R> Flow<T>.pairwiseBy( fun <T, R> Flow<T>.pairwiseBy( getInitialValue: suspend () -> T, transform: suspend (previousValue: T, newValue: T) -> R, -): Flow<R> = - onStart { emit(getInitialValue()) }.pairwiseBy(transform) +): Flow<R> = onStart { emit(getInitialValue()) }.pairwiseBy(transform) /** * Returns a new [Flow] that produces the two most recent emissions from [this]. Note that the new @@ -88,8 +89,8 @@ fun <T, R> Flow<T>.pairwiseBy( fun <T> Flow<T>.pairwise(): Flow<WithPrev<T>> = pairwiseBy(::WithPrev) /** - * Returns a new [Flow] that produces the two most recent emissions from [this]. [initialValue] - * will be used as the "old" value for the first emission. + * Returns a new [Flow] that produces the two most recent emissions from [this]. [initialValue] will + * be used as the "old" value for the first emission. * * Useful for code that needs to compare the current value to the previous value. */ @@ -102,9 +103,9 @@ data class WithPrev<T>(val previousValue: T, val newValue: T) * Returns a new [Flow] that combines the [Set] changes between each emission from [this] using * [transform]. * - * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause - * a change event to be emitted that contains no removals, and all elements from that first [Set] - * as additions. + * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause a + * change event to be emitted that contains no removals, and all elements from that first [Set] as + * additions. * * If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted * until a second [Set] has been emitted from the upstream [Flow]. @@ -112,22 +113,23 @@ data class WithPrev<T>(val previousValue: T, val newValue: T) fun <T, R> Flow<Set<T>>.setChangesBy( transform: suspend (removed: Set<T>, added: Set<T>) -> R, emitFirstEvent: Boolean = true, -): Flow<R> = (if (emitFirstEvent) onStart { emit(emptySet()) } else this) - .distinctUntilChanged() - .pairwiseBy { old: Set<T>, new: Set<T> -> - // If an element was present in the old set, but not the new one, then it was removed - val removed = old - new - // If an element is present in the new set, but on the old one, then it was added - val added = new - old - transform(removed, added) - } +): Flow<R> = + (if (emitFirstEvent) onStart { emit(emptySet()) } else this) + .distinctUntilChanged() + .pairwiseBy { old: Set<T>, new: Set<T> -> + // If an element was present in the old set, but not the new one, then it was removed + val removed = old - new + // If an element is present in the new set, but on the old one, then it was added + val added = new - old + transform(removed, added) + } /** * Returns a new [Flow] that produces the [Set] changes between each emission from [this]. * - * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause - * a change event to be emitted that contains no removals, and all elements from that first [Set] - * as additions. + * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause a + * change event to be emitted that contains no removals, and all elements from that first [Set] as + * additions. * * If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted * until a second [Set] has been emitted from the upstream [Flow]. @@ -153,14 +155,11 @@ fun <A, B, C> Flow<A>.sample(other: Flow<B>, transform: suspend (A, B) -> C): Fl coroutineScope { val noVal = Any() val sampledRef = AtomicReference(noVal) - val job = launch(Dispatchers.Unconfined) { - other.collect { sampledRef.set(it) } - } + val job = launch(Dispatchers.Unconfined) { other.collect { sampledRef.set(it) } } collect { val sampled = sampledRef.get() if (sampled != noVal) { - @Suppress("UNCHECKED_CAST") - emit(transform(it, sampled as B)) + @Suppress("UNCHECKED_CAST") emit(transform(it, sampled as B)) } } job.cancel() @@ -181,7 +180,6 @@ fun <A> Flow<*>.sample(other: Flow<A>): Flow<A> = sample(other) { _, a -> a } * latest value is emitted. * * Example: - * * ```kotlin * flow { * emit(1) // t=0ms @@ -210,7 +208,6 @@ fun <T> Flow<T>.throttle(periodMs: Long): Flow<T> = this.throttle(periodMs, Syst * during this period, only The latest value is emitted. * * Example: - * * ```kotlin * flow { * emit(1) // t=0ms @@ -248,10 +245,11 @@ fun <T> Flow<T>.throttle(periodMs: Long, clock: SystemClock): Flow<T> = channelF // We create delayJob to allow cancellation during the delay period delayJob = launch { delay(timeUntilNextEmit) - sendJob = outerScope.launch(start = CoroutineStart.UNDISPATCHED) { - send(it) - previousEmitTimeMs = clock.elapsedRealtime() - } + sendJob = + outerScope.launch(start = CoroutineStart.UNDISPATCHED) { + send(it) + previousEmitTimeMs = clock.elapsedRealtime() + } } } else { send(it) @@ -259,4 +257,15 @@ fun <T> Flow<T>.throttle(periodMs: Long, clock: SystemClock): Flow<T> = channelF } } } -}
\ No newline at end of file +} + +/** + * Returns a [StateFlow] launched in the surrounding [CoroutineScope]. This [StateFlow] gets its + * value by invoking [getValue] whenever an event is emitted from [changedSignals]. It will also + * immediately invoke [getValue] to establish its initial value. + */ +inline fun <T> CoroutineScope.stateFlow( + changedSignals: Flow<Unit>, + crossinline getValue: () -> T, +): StateFlow<T> = + changedSignals.map { getValue() }.stateIn(this, SharingStarted.Eagerly, getValue()) diff --git a/packages/SystemUI/src/com/android/systemui/util/ui/AnimatedValue.kt b/packages/SystemUI/src/com/android/systemui/util/ui/AnimatedValue.kt new file mode 100644 index 000000000000..51d2afabd7f9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/ui/AnimatedValue.kt @@ -0,0 +1,62 @@ +/* + * 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. + */ +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.util.ui + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.transformLatest + +/** + * A state comprised of a [value] of type [T] paired with a boolean indicating whether or not the + * [value] [isAnimating] in the UI. + */ +data class AnimatedValue<T>( + val value: T, + val isAnimating: Boolean, +) + +/** + * An event comprised of a [value] of type [T] paired with a [boolean][startAnimating] indicating + * whether or not this event should start an animation. + */ +data class AnimatableEvent<T>( + val value: T, + val startAnimating: Boolean, +) + +/** + * Returns a [Flow] that tracks an [AnimatedValue] state. The input [Flow] is used to update the + * [AnimatedValue.value], as well as [AnimatedValue.isAnimating] if the event's + * [AnimatableEvent.startAnimating] value is `true`. When [completionEvents] emits a value, the + * [AnimatedValue.isAnimating] will flip to `false`. + */ +fun <T> Flow<AnimatableEvent<T>>.toAnimatedValueFlow( + completionEvents: Flow<Any?>, +): Flow<AnimatedValue<T>> = transformLatest { (value, startAnimating) -> + emit(AnimatedValue(value, isAnimating = startAnimating)) + if (startAnimating) { + // Wait for a completion now that we've started animating + completionEvents + .map { Unit } // replace the event so that it's never `null` + .firstOrNull() // `null` indicates an empty flow + // emit the new state if the flow was not empty. + ?.run { emit(AnimatedValue(value, isAnimating = false)) } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index ea4d31bca035..d65a69c62072 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -77,6 +77,8 @@ import com.android.systemui.util.RingerModeLiveData; import com.android.systemui.util.RingerModeTracker; import com.android.systemui.util.concurrency.ThreadFactory; +import dalvik.annotation.optimization.NeverCompile; + import java.io.PrintWriter; import java.util.HashMap; import java.util.List; @@ -286,6 +288,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa return new MediaSessions(context, looper, callbacks); } + @NeverCompile public void dump(PrintWriter pw, String[] args) { pw.println(VolumeDialogControllerImpl.class.getSimpleName() + " state:"); pw.print(" mVolumePolicy: "); pw.println(mVolumePolicy); diff --git a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt index c1be44ab8a85..167e3417c162 100644 --- a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt +++ b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt @@ -81,7 +81,7 @@ data class TestMocksModule( @get:Provides val notificationStackSizeCalculator: NotificationStackSizeCalculator = mock(), @get:Provides val notificationWakeUpCoordinator: NotificationWakeUpCoordinator = mock(), @get:Provides val screenLifecycle: ScreenLifecycle = mock(), - @get:Provides val screenOffAnimController: ScreenOffAnimationController = mock(), + @get:Provides val screenOffAnimationController: ScreenOffAnimationController = mock(), @get:Provides val scrimController: ScrimController = mock(), @get:Provides val statusBarStateController: SysuiStatusBarStateController = mock(), @get:Provides val statusBarWindowController: StatusBarWindowController = mock(), diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java index 989164ebf174..3b8e02f7455a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java @@ -20,7 +20,6 @@ import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.animation.LayoutTransition; import android.view.View; import android.view.ViewTreeObserver; import android.widget.FrameLayout; @@ -69,7 +68,6 @@ public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase { @Mock protected KeyguardClockSwitch mKeyguardClockSwitch; @Mock protected FrameLayout mMediaHostContainer; - @Mock protected LayoutTransition mMediaLayoutTransition; @Before public void setup() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java index e4e2b0a8d89f..948942fbce3a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java @@ -16,22 +16,27 @@ package com.android.keyguard; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; 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; -import android.animation.LayoutTransition; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.View; -import com.android.systemui.res.R; +import com.android.app.animation.Interpolators; +import com.android.systemui.animation.ViewHierarchyAnimator; import com.android.systemui.plugins.ClockConfig; import com.android.systemui.plugins.ClockController; +import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; @@ -39,6 +44,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import java.lang.reflect.Field; + @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) @RunWith(AndroidTestingRunner.class) @@ -81,7 +88,7 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll public void updatePosition_primaryClockAnimation() { ClockController mockClock = mock(ClockController.class); when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock); - when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", false, true)); + when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", "", "", false, true)); mController.updatePosition(10, 15, 20f, true); @@ -96,7 +103,7 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll public void updatePosition_alternateClockAnimation() { ClockController mockClock = mock(ClockController.class); when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock); - when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", true, true)); + when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", "", "", true, true)); mController.updatePosition(10, 15, 20f, true); @@ -142,19 +149,7 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll } @Test - public void onInit_addsOnLayoutChangeListenerToMediaHostContainer() { - when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn( - mMediaHostContainer); - - mController.onInit(); - - ArgumentCaptor<View.OnLayoutChangeListener> captor = - ArgumentCaptor.forClass(View.OnLayoutChangeListener.class); - verify(mMediaHostContainer).addOnLayoutChangeListener(captor.capture()); - } - - @Test - public void clockSwitchHeightChanged_mediaChangingLayoutTransitionEnabled() { + public void clockSwitchHeightChanged_animatesMediaHostContainer() { when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn( mMediaHostContainer); @@ -167,6 +162,10 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll // Above here is the same as `onInit_addsOnLayoutChangeListenerToClockSwitch`. // Below here is the actual test. + ViewHierarchyAnimator.Companion animator = ViewHierarchyAnimator.Companion; + ViewHierarchyAnimator.Companion spiedAnimator = spy(animator); + setCompanion(spiedAnimator); + View.OnLayoutChangeListener listener = captor.getValue(); mController.setSplitShadeEnabled(true); @@ -174,17 +173,20 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll when(mKeyguardUpdateMonitor.isKeyguardVisible()).thenReturn(true); when(mMediaHostContainer.getVisibility()).thenReturn(View.VISIBLE); when(mMediaHostContainer.getHeight()).thenReturn(200); - when(mMediaHostContainer.getLayoutTransition()).thenReturn(mMediaLayoutTransition); when(mKeyguardClockSwitch.getHeight()).thenReturn(0); listener.onLayoutChange(mKeyguardClockSwitch, /* left= */ 0, /* top= */ 0, /* right= */ 0, /* bottom= */ 0, /* oldLeft= */ 0, /* oldTop= */ 0, /* oldRight= */ 0, /* oldBottom = */ 200); - verify(mMediaLayoutTransition).enableTransitionType(LayoutTransition.CHANGING); + verify(spiedAnimator).animateNextUpdate(mMediaHostContainer, + Interpolators.STANDARD, /* duration= */ 500L, /* animateChildren= */ false); + + // Resets ViewHierarchyAnimator.Companion to its original value + setCompanion(animator); } @Test - public void clockSwitchHeightNotChanged_mediaChangingLayoutTransitionNotEnabled() { + public void clockSwitchHeightNotChanged_doesNotAnimateMediaOutputContainer() { when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn( mMediaHostContainer); @@ -197,6 +199,10 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll // Above here is the same as `onInit_addsOnLayoutChangeListenerToClockSwitch`. // Below here is the actual test. + ViewHierarchyAnimator.Companion animator = ViewHierarchyAnimator.Companion; + ViewHierarchyAnimator.Companion spiedAnimator = spy(animator); + setCompanion(spiedAnimator); + View.OnLayoutChangeListener listener = captor.getValue(); mController.setSplitShadeEnabled(true); @@ -204,36 +210,24 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll when(mKeyguardUpdateMonitor.isKeyguardVisible()).thenReturn(true); when(mMediaHostContainer.getVisibility()).thenReturn(View.VISIBLE); when(mMediaHostContainer.getHeight()).thenReturn(200); - when(mMediaHostContainer.getLayoutTransition()).thenReturn(mMediaLayoutTransition); when(mKeyguardClockSwitch.getHeight()).thenReturn(200); listener.onLayoutChange(mKeyguardClockSwitch, /* left= */ 0, /* top= */ 0, /* right= */ 0, /* bottom= */ 0, /* oldLeft= */ 0, /* oldTop= */ 0, /* oldRight= */ 0, /* oldBottom = */ 200); - verify(mMediaLayoutTransition, never()).enableTransitionType(LayoutTransition.CHANGING); - } - - @Test - public void onMediaHostContainerLayout_disablesChangingLayoutTransition() { - when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn( - mMediaHostContainer); - - mController.onInit(); + verify(spiedAnimator, never()).animateNextUpdate(any(), any(), anyLong(), anyBoolean()); - ArgumentCaptor<View.OnLayoutChangeListener> captor = - ArgumentCaptor.forClass(View.OnLayoutChangeListener.class); - verify(mMediaHostContainer).addOnLayoutChangeListener(captor.capture()); - - // Above here is the same as `onInit_addsOnLayoutChangeListenerToMediaHostContainer`. - // Below here is the actual test. - - View.OnLayoutChangeListener listener = captor.getValue(); - - when(mMediaHostContainer.getLayoutTransition()).thenReturn(mMediaLayoutTransition); + // Resets ViewHierarchyAnimator.Companion to its original value + setCompanion(animator); + } - when(mMediaLayoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGING)).thenReturn( - true); - listener.onLayoutChange(mMediaHostContainer, 1, 2, 3, 4, 1, 2, 3, 4); - verify(mMediaLayoutTransition).disableTransitionType(LayoutTransition.CHANGING); + private void setCompanion(ViewHierarchyAnimator.Companion companion) { + try { + Field field = ViewHierarchyAnimator.class.getDeclaredField("Companion"); + field.setAccessible(true); + field.set(null, companion); + } catch (Exception e) { + throw new RuntimeException(e); + } } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt index 58d372c68c55..86439e557f8b 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt @@ -1,6 +1,5 @@ package com.android.keyguard -import android.animation.LayoutTransition import android.test.suitebuilder.annotation.SmallTest import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper @@ -36,20 +35,6 @@ class KeyguardStatusViewTest : SysuiTestCase() { } @Test - fun mediaViewHasLayoutTransitionInDisabledState() { - val layoutTransition = (mediaView as ViewGroup).layoutTransition - assertThat(layoutTransition).isNotNull() - assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGE_APPEARING)) - .isFalse() - assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGE_DISAPPEARING)) - .isFalse() - assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.APPEARING)).isFalse() - assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.DISAPPEARING)) - .isFalse() - assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGING)).isFalse() - } - - @Test fun setChildrenTranslationYExcludingMediaView_mediaViewIsNotTranslated() { val translationY = 1234f diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java index ce1930a6e80f..d61ca697642a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java @@ -42,6 +42,7 @@ import android.view.accessibility.AccessibilityManager; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.AuthRippleController; +import com.android.systemui.bouncer.domain.interactor.BouncerInteractor; import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.doze.util.BurnInHelperKt; import com.android.systemui.dump.DumpManager; @@ -51,6 +52,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.res.R; +import com.android.systemui.scene.SceneTestUtils; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -75,6 +77,8 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase { protected MockitoSession mStaticMockSession; + protected final SceneTestUtils mSceneTestUtils = new SceneTestUtils(this); + protected @Mock BouncerInteractor mBouncerInteractor; protected @Mock LockIconView mLockIconView; protected @Mock AnimatedStateListDrawable mIconDrawable; protected @Mock Context mContext; @@ -93,6 +97,7 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase { protected @Mock AuthRippleController mAuthRippleController; protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock()); protected FakeFeatureFlags mFeatureFlags; + protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor; protected LockIconViewController mUnderTest; @@ -148,6 +153,7 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase { mFeatureFlags.set(MIGRATE_LOCK_ICON, false); mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false); mFeatureFlags.set(LOCKSCREEN_ENABLE_LANDSCAPE, false); + mUnderTest = new LockIconViewController( mStatusBarStateController, mKeyguardUpdateMonitor, @@ -168,7 +174,9 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase { KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(), mFeatureFlags, mPrimaryBouncerInteractor, - mContext + mContext, + () -> mBouncerInteractor, + mSceneTestUtils.getSceneContainerFlags() ); } @@ -227,8 +235,8 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase { setupLockIconViewMocks(); } - protected void init(boolean useMigrationFlag) { - mFeatureFlags.set(DOZING_MIGRATION_1, useMigrationFlag); + protected void init(boolean useDozeMigrationFlag) { + mFeatureFlags.set(DOZING_MIGRATION_1, useDozeMigrationFlag); mUnderTest.setLockIconView(mLockIconView); } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java index 7b920939263e..4bacc3dfca0d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java @@ -26,6 +26,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -404,6 +405,49 @@ public class LockIconViewControllerTest extends LockIconViewControllerBaseTest { // THEN uses perform haptic feedback verify(mVibrator).performHapticFeedback(any(), eq(UdfpsController.LONG_PRESS)); + } + + @Test + public void longPress_showBouncer_sceneContainerNotEnabled() { + init(/* useMigrationFlag= */ false); + mSceneTestUtils.getSceneContainerFlags().setEnabled(false); + mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); + when(mFalsingManager.isFalseLongTap(anyInt())).thenReturn(false); + + // WHEN longPress + mUnderTest.onLongPress(); + + // THEN show primary bouncer via keyguard view controller, not scene container + verify(mKeyguardViewController).showPrimaryBouncer(anyBoolean()); + verify(mBouncerInteractor, never()).showOrUnlockDevice(any()); + } + + @Test + public void longPress_showBouncer() { + init(/* useMigrationFlag= */ false); + mSceneTestUtils.getSceneContainerFlags().setEnabled(true); + mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); + when(mFalsingManager.isFalseLongTap(anyInt())).thenReturn(false); + + // WHEN longPress + mUnderTest.onLongPress(); + + // THEN show primary bouncer + verify(mKeyguardViewController, never()).showPrimaryBouncer(anyBoolean()); + verify(mBouncerInteractor).showOrUnlockDevice(any()); + } + + @Test + public void longPress_falsingTriggered_doesNotShowBouncer() { + init(/* useMigrationFlag= */ false); + mSceneTestUtils.getSceneContainerFlags().setEnabled(true); + mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); + when(mFalsingManager.isFalseLongTap(anyInt())).thenReturn(true); + + // WHEN longPress + mUnderTest.onLongPress(); + // THEN don't show primary bouncer + verify(mBouncerInteractor, never()).showOrUnlockDevice(any()); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt index 59c7e7669b63..8faf715521f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt @@ -166,6 +166,9 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() { waitForIdleSync() verify(controller).onLaunchAnimationCancelled() verify(controller, never()).onLaunchAnimationStart(anyBoolean()) + verify(listener).onLaunchAnimationCancelled() + verify(listener, never()).onLaunchAnimationStart() + assertNull(runner.delegate) } @Test @@ -176,6 +179,9 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() { waitForIdleSync() verify(controller).onLaunchAnimationCancelled() verify(controller, never()).onLaunchAnimationStart(anyBoolean()) + verify(listener).onLaunchAnimationCancelled() + verify(listener, never()).onLaunchAnimationStart() + assertNull(runner.delegate) } @Test @@ -194,6 +200,15 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() { } } + @Test + fun disposeRunner_delegateDereferenced() { + val runner = activityLaunchAnimator.createRunner(controller) + assertNotNull(runner.delegate) + runner.dispose() + waitForIdleSync() + assertNull(runner.delegate) + } + private fun fakeWindow(): RemoteAnimationTarget { val bounds = Rect(10 /* left */, 20 /* top */, 30 /* right */, 40 /* bottom */) val taskInfo = ActivityManager.RunningTaskInfo() diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt index a7e7dd074a33..2b51ac5e3187 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.animation import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import androidx.core.animation.doOnEnd +import androidx.test.filters.FlakyTest import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.util.doOnEnd @@ -30,6 +31,7 @@ import org.junit.runner.RunWith @RunWith(AndroidTestingRunner::class) @SmallTest @RunWithLooper +@FlakyTest(bugId = 302149604) class AnimatorTestRuleOrderTest : SysuiTestCase() { @get:Rule val animatorTestRule = AnimatorTestRule() diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt index 679dfefae7cd..2c80035873f0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt @@ -12,6 +12,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.runBlocking @@ -22,6 +23,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @@ -54,6 +56,7 @@ class DeviceEntryRepositoryTest : SysuiTestCase() { keyguardBypassController = keyguardBypassController, keyguardStateController = keyguardStateController, ) + testScope.runCurrent() } @Test @@ -66,8 +69,7 @@ class DeviceEntryRepositoryTest : SysuiTestCase() { assertThat(isUnlocked).isFalse() val captor = argumentCaptor<KeyguardStateController.Callback>() - Mockito.verify(keyguardStateController, Mockito.atLeastOnce()) - .addCallback(captor.capture()) + verify(keyguardStateController, Mockito.atLeastOnce()).addCallback(captor.capture()) whenever(keyguardStateController.isUnlocked).thenReturn(true) captor.value.onUnlockedChanged() @@ -98,7 +100,12 @@ class DeviceEntryRepositoryTest : SysuiTestCase() { testScope.runTest { whenever(keyguardBypassController.isBypassEnabled).thenAnswer { false } whenever(keyguardBypassController.bypassEnabled).thenAnswer { false } - assertThat(underTest.isBypassEnabled()).isFalse() + withArgCaptor { + verify(keyguardBypassController).registerOnBypassStateChangedListener(capture()) + } + .onBypassStateChanged(false) + runCurrent() + assertThat(underTest.isBypassEnabled.value).isFalse() } @Test @@ -106,7 +113,12 @@ class DeviceEntryRepositoryTest : SysuiTestCase() { testScope.runTest { whenever(keyguardBypassController.isBypassEnabled).thenAnswer { true } whenever(keyguardBypassController.bypassEnabled).thenAnswer { true } - assertThat(underTest.isBypassEnabled()).isTrue() + withArgCaptor { + verify(keyguardBypassController).registerOnBypassStateChangedListener(capture()) + } + .onBypassStateChanged(true) + runCurrent() + assertThat(underTest.isBypassEnabled.value).isTrue() } companion object { diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt index c4cd8a4de8ab..c13fde75a068 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt @@ -218,14 +218,14 @@ class DeviceEntryInteractorTest : SysuiTestCase() { fun isBypassEnabled_enabledInRepository_true() = testScope.runTest { utils.deviceEntryRepository.setBypassEnabled(true) - assertThat(underTest.isBypassEnabled()).isTrue() + assertThat(underTest.isBypassEnabled.value).isTrue() } @Test fun isBypassEnabled_disabledInRepository_false() = testScope.runTest { utils.deviceEntryRepository.setBypassEnabled(false) - assertThat(underTest.isBypassEnabled()).isFalse() + assertThat(underTest.isBypassEnabled.value).isFalse() } private fun switchToScene(sceneKey: SceneKey) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt index 632d149c9520..f37306276848 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt @@ -16,23 +16,17 @@ package com.android.systemui.keyevent.domain.interactor -import android.view.KeyEvent import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.back.domain.interactor.BackActionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory -import com.android.systemui.keyguard.domain.interactor.KeyguardKeyEventInteractor -import com.android.systemui.util.mockito.eq -import com.android.systemui.util.mockito.whenever +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyevent.data.repository.FakeKeyEventRepository 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.Mock -import org.mockito.Mockito.never -import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit @SmallTest @@ -40,108 +34,27 @@ import org.mockito.junit.MockitoJUnit class KeyEventInteractorTest : SysuiTestCase() { @JvmField @Rule var mockitoRule = MockitoJUnit.rule() - private lateinit var keyguardInteractorWithDependencies: - KeyguardInteractorFactory.WithDependencies - @Mock private lateinit var keyguardKeyEventInteractor: KeyguardKeyEventInteractor - @Mock private lateinit var backActionInteractor: BackActionInteractor + private lateinit var repository: FakeKeyEventRepository private lateinit var underTest: KeyEventInteractor @Before fun setup() { - keyguardInteractorWithDependencies = KeyguardInteractorFactory.create() + repository = FakeKeyEventRepository() underTest = KeyEventInteractor( - backActionInteractor, - keyguardKeyEventInteractor, + repository, ) } @Test - fun dispatchBackKey_notHandledByKeyguardKeyEventInteractor_handledByBackActionInteractor() { - val backKeyEventActionDown = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK) - val backKeyEventActionUp = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK) - - // GIVEN back key ACTION_DOWN and ACTION_UP aren't handled by the keyguardKeyEventInteractor - whenever(keyguardKeyEventInteractor.dispatchKeyEvent(backKeyEventActionDown)) - .thenReturn(false) - whenever(keyguardKeyEventInteractor.dispatchKeyEvent(backKeyEventActionUp)) - .thenReturn(false) - - // WHEN back key event ACTION_DOWN, the event is handled even though back isn't requested - assertThat(underTest.dispatchKeyEvent(backKeyEventActionDown)).isTrue() - // THEN back event isn't handled on ACTION_DOWN - verify(backActionInteractor, never()).onBackRequested() - - // WHEN back key event ACTION_UP - assertThat(underTest.dispatchKeyEvent(backKeyEventActionUp)).isTrue() - // THEN back event is handled on ACTION_UP - verify(backActionInteractor).onBackRequested() - } - - @Test - fun dispatchKeyEvent_isNotHandledByKeyguardKeyEventInteractor() { - val keyEvent = - KeyEvent( - KeyEvent.ACTION_UP, - KeyEvent.KEYCODE_SPACE, - ) - whenever(keyguardKeyEventInteractor.dispatchKeyEvent(eq(keyEvent))).thenReturn(false) - assertThat(underTest.dispatchKeyEvent(keyEvent)).isFalse() - } - - @Test - fun dispatchKeyEvent_handledByKeyguardKeyEventInteractor() { - val keyEvent = - KeyEvent( - KeyEvent.ACTION_UP, - KeyEvent.KEYCODE_SPACE, - ) - whenever(keyguardKeyEventInteractor.dispatchKeyEvent(eq(keyEvent))).thenReturn(true) - assertThat(underTest.dispatchKeyEvent(keyEvent)).isTrue() - } - - @Test - fun interceptMediaKey_isNotHandledByKeyguardKeyEventInteractor() { - val keyEvent = - KeyEvent( - KeyEvent.ACTION_UP, - KeyEvent.KEYCODE_SPACE, - ) - whenever(keyguardKeyEventInteractor.interceptMediaKey(eq(keyEvent))).thenReturn(false) - assertThat(underTest.interceptMediaKey(keyEvent)).isFalse() - } - - @Test - fun interceptMediaKey_handledByKeyguardKeyEventInteractor() { - val keyEvent = - KeyEvent( - KeyEvent.ACTION_UP, - KeyEvent.KEYCODE_SPACE, - ) - whenever(keyguardKeyEventInteractor.interceptMediaKey(eq(keyEvent))).thenReturn(true) - assertThat(underTest.interceptMediaKey(keyEvent)).isTrue() - } - - @Test - fun dispatchKeyEventPreIme_isNotHandledByKeyguardKeyEventInteractor() { - val keyEvent = - KeyEvent( - KeyEvent.ACTION_UP, - KeyEvent.KEYCODE_SPACE, - ) - whenever(keyguardKeyEventInteractor.dispatchKeyEventPreIme(eq(keyEvent))).thenReturn(false) - assertThat(underTest.dispatchKeyEventPreIme(keyEvent)).isFalse() - } - - @Test - fun dispatchKeyEventPreIme_handledByKeyguardKeyEventInteractor() { - val keyEvent = - KeyEvent( - KeyEvent.ACTION_UP, - KeyEvent.KEYCODE_SPACE, - ) - whenever(keyguardKeyEventInteractor.dispatchKeyEventPreIme(eq(keyEvent))).thenReturn(true) - assertThat(underTest.dispatchKeyEventPreIme(keyEvent)).isTrue() - } + fun dispatchBackKey_notHandledByKeyguardKeyEventInteractor_handledByBackActionInteractor() = + runTest { + val isPowerDown by collectLastValue(underTest.isPowerButtonDown) + repository.setPowerButtonDown(false) + assertThat(isPowerDown).isFalse() + + repository.setPowerButtonDown(true) + assertThat(isPowerDown).isTrue() + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt new file mode 100644 index 000000000000..af00a48d571b --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt @@ -0,0 +1,147 @@ +/* + * 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 com.android.systemui.keyevent.domain.interactor + +import android.view.KeyEvent +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.back.domain.interactor.BackActionInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory +import com.android.systemui.keyguard.domain.interactor.KeyguardKeyEventInteractor +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.junit.MockitoJUnit + +@SmallTest +@RunWith(AndroidJUnit4::class) +class SysUIKeyEventHandlerTest : SysuiTestCase() { + @JvmField @Rule var mockitoRule = MockitoJUnit.rule() + + private lateinit var keyguardInteractorWithDependencies: + KeyguardInteractorFactory.WithDependencies + @Mock private lateinit var keyguardKeyEventInteractor: KeyguardKeyEventInteractor + @Mock private lateinit var backActionInteractor: BackActionInteractor + + private lateinit var underTest: SysUIKeyEventHandler + + @Before + fun setup() { + keyguardInteractorWithDependencies = KeyguardInteractorFactory.create() + underTest = + SysUIKeyEventHandler( + backActionInteractor, + keyguardKeyEventInteractor, + ) + } + + @Test + fun dispatchBackKey_notHandledByKeyguardKeyEventInteractor_handledByBackActionInteractor() { + val backKeyEventActionDown = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK) + val backKeyEventActionUp = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK) + + // GIVEN back key ACTION_DOWN and ACTION_UP aren't handled by the keyguardKeyEventInteractor + whenever(keyguardKeyEventInteractor.dispatchKeyEvent(backKeyEventActionDown)) + .thenReturn(false) + whenever(keyguardKeyEventInteractor.dispatchKeyEvent(backKeyEventActionUp)) + .thenReturn(false) + + // WHEN back key event ACTION_DOWN, the event is handled even though back isn't requested + assertThat(underTest.dispatchKeyEvent(backKeyEventActionDown)).isTrue() + // THEN back event isn't handled on ACTION_DOWN + verify(backActionInteractor, never()).onBackRequested() + + // WHEN back key event ACTION_UP + assertThat(underTest.dispatchKeyEvent(backKeyEventActionUp)).isTrue() + // THEN back event is handled on ACTION_UP + verify(backActionInteractor).onBackRequested() + } + + @Test + fun dispatchKeyEvent_isNotHandledByKeyguardKeyEventInteractor() { + val keyEvent = + KeyEvent( + KeyEvent.ACTION_UP, + KeyEvent.KEYCODE_SPACE, + ) + whenever(keyguardKeyEventInteractor.dispatchKeyEvent(eq(keyEvent))).thenReturn(false) + assertThat(underTest.dispatchKeyEvent(keyEvent)).isFalse() + } + + @Test + fun dispatchKeyEvent_handledByKeyguardKeyEventInteractor() { + val keyEvent = + KeyEvent( + KeyEvent.ACTION_UP, + KeyEvent.KEYCODE_SPACE, + ) + whenever(keyguardKeyEventInteractor.dispatchKeyEvent(eq(keyEvent))).thenReturn(true) + assertThat(underTest.dispatchKeyEvent(keyEvent)).isTrue() + } + + @Test + fun interceptMediaKey_isNotHandledByKeyguardKeyEventInteractor() { + val keyEvent = + KeyEvent( + KeyEvent.ACTION_UP, + KeyEvent.KEYCODE_SPACE, + ) + whenever(keyguardKeyEventInteractor.interceptMediaKey(eq(keyEvent))).thenReturn(false) + assertThat(underTest.interceptMediaKey(keyEvent)).isFalse() + } + + @Test + fun interceptMediaKey_handledByKeyguardKeyEventInteractor() { + val keyEvent = + KeyEvent( + KeyEvent.ACTION_UP, + KeyEvent.KEYCODE_SPACE, + ) + whenever(keyguardKeyEventInteractor.interceptMediaKey(eq(keyEvent))).thenReturn(true) + assertThat(underTest.interceptMediaKey(keyEvent)).isTrue() + } + + @Test + fun dispatchKeyEventPreIme_isNotHandledByKeyguardKeyEventInteractor() { + val keyEvent = + KeyEvent( + KeyEvent.ACTION_UP, + KeyEvent.KEYCODE_SPACE, + ) + whenever(keyguardKeyEventInteractor.dispatchKeyEventPreIme(eq(keyEvent))).thenReturn(false) + assertThat(underTest.dispatchKeyEventPreIme(keyEvent)).isFalse() + } + + @Test + fun dispatchKeyEventPreIme_handledByKeyguardKeyEventInteractor() { + val keyEvent = + KeyEvent( + KeyEvent.ACTION_UP, + KeyEvent.KEYCODE_SPACE, + ) + whenever(keyguardKeyEventInteractor.dispatchKeyEventPreIme(eq(keyEvent))).thenReturn(true) + assertThat(underTest.dispatchKeyEventPreIme(keyEvent)).isTrue() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt index bbe68234f055..e10815d9de61 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt @@ -35,6 +35,7 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi import org.junit.Before import org.junit.Rule import org.junit.Test @@ -46,6 +47,7 @@ import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit +@ExperimentalCoroutinesApi @SmallTest @RunWith(AndroidJUnit4::class) class KeyguardKeyEventInteractorTest : SysuiTestCase() { @@ -57,8 +59,6 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() { KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP) private val backKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK) - private lateinit var keyguardInteractorWithDependencies: - KeyguardInteractorFactory.WithDependencies private lateinit var powerInteractor: PowerInteractor @Mock private lateinit var statusBarStateController: StatusBarStateController @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager @@ -73,14 +73,12 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() { fun setup() { whenever(mediaSessionLegacyHelperWrapper.getHelper(any())) .thenReturn(mediaSessionLegacyHelper) - keyguardInteractorWithDependencies = KeyguardInteractorFactory.create() powerInteractor = PowerInteractorFactory.create().powerInteractor underTest = KeyguardKeyEventInteractor( context, statusBarStateController, - keyguardInteractorWithDependencies.keyguardInteractor, statusBarKeyguardViewManager, shadeController, mediaSessionLegacyHelperWrapper, @@ -132,58 +130,73 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() { } @Test - fun dispatchKeyEvent_menuActionUp_interactiveKeyguard_collapsesShade() { + fun dispatchKeyEvent_menuActionUp_awakeKeyguard_showsPrimaryBouncer() { powerInteractor.setAwakeForTest() whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true) - val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU) - assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue() - verify(shadeController).animateCollapseShadeForced() + verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_MENU) } @Test - fun dispatchKeyEvent_menuActionUp_interactiveShadeLocked_collapsesShade() { + fun dispatchKeyEvent_menuActionUp_awakeShadeLocked_collapsesShade() { powerInteractor.setAwakeForTest() whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED) whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true) - // action down: does NOT collapse the shade - val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU) - assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse() - verify(shadeController, never()).animateCollapseShadeForced() - - // action up: collapses the shade - val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU) - assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue() - verify(shadeController).animateCollapseShadeForced() + verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_MENU) } @Test - fun dispatchKeyEvent_menuActionUp_nonInteractiveKeyguard_neverCollapsesShade() { + fun dispatchKeyEvent_menuActionUp_asleepKeyguard_neverCollapsesShade() { powerInteractor.setAsleepForTest() whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true) - val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU) - assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isFalse() - verify(shadeController, never()).animateCollapseShadeForced() + verifyActionsDoNothing(KeyEvent.KEYCODE_MENU) } @Test - fun dispatchKeyEvent_spaceActionUp_interactiveKeyguard_collapsesShade() { + fun dispatchKeyEvent_spaceActionUp_awakeKeyguard_collapsesShade() { powerInteractor.setAwakeForTest() whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + whenever(statusBarKeyguardViewManager.primaryBouncerIsShowing()).thenReturn(false) - // action down: does NOT collapse the shade - val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE) - assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse() - verify(shadeController, never()).animateCollapseShadeForced() + verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_SPACE) + } - // action up: collapses the shade - val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE) - assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue() - verify(shadeController).animateCollapseShadeForced() + @Test + fun dispatchKeyEvent_spaceActionUp_shadeLocked_collapsesShade() { + powerInteractor.setAwakeForTest() + whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED) + + verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_SPACE) + } + + @Test + fun dispatchKeyEvent_enterActionUp_awakeKeyguard_showsPrimaryBouncer() { + powerInteractor.setAwakeForTest() + whenever(statusBarKeyguardViewManager.primaryBouncerIsShowing()).thenReturn(false) + whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + + verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_ENTER) + } + + @Test + fun dispatchKeyEvent_enterActionUp_awakeKeyguard_primaryBouncerAlreadyShowing() { + powerInteractor.setAwakeForTest() + whenever(statusBarKeyguardViewManager.primaryBouncerIsShowing()).thenReturn(true) + whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + + verifyActionsDoNothing(KeyEvent.KEYCODE_ENTER) + } + + @Test + fun dispatchKeyEvent_enterActionUp_shadeLocked_collapsesShade() { + powerInteractor.setAwakeForTest() + whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED) + + verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_ENTER) } @Test @@ -253,4 +266,42 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() { .isFalse() verify(statusBarKeyguardViewManager, never()).interceptMediaKey(any()) } + + private fun verifyActionUpCollapsesTheShade(keycode: Int) { + // action down: does NOT collapse the shade + val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode) + assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse() + verify(shadeController, never()).animateCollapseShadeForced() + + // action up: collapses the shade + val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode) + assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue() + verify(shadeController).animateCollapseShadeForced() + } + + private fun verifyActionUpShowsPrimaryBouncer(keycode: Int) { + // action down: does NOT collapse the shade + val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode) + assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse() + verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any()) + + // action up: collapses the shade + val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode) + assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue() + verify(statusBarKeyguardViewManager).showPrimaryBouncer(eq(true)) + } + + private fun verifyActionsDoNothing(keycode: Int) { + // action down: does nothing + val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode) + assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse() + verify(shadeController, never()).animateCollapseShadeForced() + verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any()) + + // action up: doesNothing + val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode) + assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isFalse() + verify(shadeController, never()).animateCollapseShadeForced() + verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any()) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt index 906420d03bed..9630ee32d456 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt @@ -46,6 +46,7 @@ class TaskPreviewSizeProviderTest : SysuiTestCase() { private val mockContext = mock<Context>() private val resources = mock<Resources>() private val windowManager = mock<WindowManager>() + private val windowMetricsProvider = mock<WindowMetricsProvider>() private val sizeUpdates = arrayListOf<Rect>() private val testConfigurationController = FakeConfigurationController() @@ -112,13 +113,12 @@ class TaskPreviewSizeProviderTest : SysuiTestCase() { } private fun givenTaskbarSize(size: Int) { - val windowInsets = - WindowInsets.Builder() - .setInsets(Type.tappableElement(), Insets.of(Rect(0, 0, 0, size))) - .build() + val insets = Insets.of(Rect(0, 0, 0, size)) + val windowInsets = WindowInsets.Builder().setInsets(Type.tappableElement(), insets).build() val windowMetrics = WindowMetrics(windowManager.maximumWindowMetrics.bounds, windowInsets) whenever(windowManager.maximumWindowMetrics).thenReturn(windowMetrics) whenever(windowManager.currentWindowMetrics).thenReturn(windowMetrics) + whenever(windowMetricsProvider.currentWindowInsets).thenReturn(insets) } private fun givenDisplay(width: Int, height: Int, isTablet: Boolean = false) { @@ -126,6 +126,7 @@ class TaskPreviewSizeProviderTest : SysuiTestCase() { val windowMetrics = WindowMetrics(bounds, { null }, 1.0f) whenever(windowManager.maximumWindowMetrics).thenReturn(windowMetrics) whenever(windowManager.currentWindowMetrics).thenReturn(windowMetrics) + whenever(windowMetricsProvider.maximumWindowBounds).thenReturn(bounds) val minDimension = min(width, height) @@ -147,7 +148,11 @@ class TaskPreviewSizeProviderTest : SysuiTestCase() { } } - return TaskPreviewSizeProvider(mockContext, windowManager, testConfigurationController) + return TaskPreviewSizeProvider( + mockContext, + windowMetricsProvider, + testConfigurationController + ) .also { it.addCallback(listener) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt new file mode 100644 index 000000000000..fe18454ec06c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt @@ -0,0 +1,44 @@ +package com.android.systemui.mediaprojection.appselector.view + +import android.graphics.Insets +import android.graphics.Rect +import android.view.WindowManager +import android.view.WindowMetrics +import androidx.core.view.WindowInsetsCompat +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import org.junit.Test + +@SmallTest +class WindowMetricsProviderImplTest : SysuiTestCase() { + + private val windowManager = mock<WindowManager>() + private val windowMetricsProvider = WindowMetricsProviderImpl(windowManager) + + @Test + fun getMaximumWindowBounds_returnsValueFromWMMaxWindowMetrics() { + val bounds = Rect(/* left= */ 100, /* top= */ 200, /* right= */ 300, /* bottom= */ 400) + val metrics = + WindowMetrics(bounds, /* windowInsetsSupplier= */ { null }, /* density= */ 1.0f) + whenever(windowManager.maximumWindowMetrics).thenReturn(metrics) + + assertThat(windowMetricsProvider.maximumWindowBounds).isEqualTo(bounds) + } + + @Test + fun getCurrentWindowInsets_returnsFromWMCurrentWindowMetrics() { + val bounds = Rect() + val insets = + Insets.of(Rect(/* left= */ 123, /* top= */ 456, /* right= */ 789, /* bottom= */ 1012)) + val windowInsets = + android.view.WindowInsets.Builder() + .setInsets(WindowInsetsCompat.Type.tappableElement(), insets) + .build() + whenever(windowManager.currentWindowMetrics).thenReturn(WindowMetrics(bounds, windowInsets)) + + assertThat(windowMetricsProvider.currentWindowInsets).isEqualTo(insets) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt index b4f9e8dcfb39..677d9db0b97c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -49,7 +49,7 @@ import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.flags.SystemPropertiesHelper -import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor +import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.KeyguardUnlockAnimationController import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository @@ -144,7 +144,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { @Mock lateinit var dragDownHelper: DragDownHelper @Mock lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel - @Mock lateinit var keyEventInteractor: KeyEventInteractor + @Mock lateinit var sysUIKeyEventHandler: SysUIKeyEventHandler @Mock lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor @Mock lateinit var alternateBouncerInteractor: AlternateBouncerInteractor private val notificationExpansionRepository = NotificationExpansionRepository() @@ -251,7 +251,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { securityModel = mock(KeyguardSecurityModel::class.java), ), BouncerLogger(logcatLogBuffer("BouncerLog")), - keyEventInteractor, + sysUIKeyEventHandler, primaryBouncerInteractor, alternateBouncerInteractor, ) @@ -475,21 +475,21 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { fun forwardsDispatchKeyEvent() { val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B) interactionEventHandler.dispatchKeyEvent(keyEvent) - verify(keyEventInteractor).dispatchKeyEvent(keyEvent) + verify(sysUIKeyEventHandler).dispatchKeyEvent(keyEvent) } @Test fun forwardsDispatchKeyEventPreIme() { val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B) interactionEventHandler.dispatchKeyEventPreIme(keyEvent) - verify(keyEventInteractor).dispatchKeyEventPreIme(keyEvent) + verify(sysUIKeyEventHandler).dispatchKeyEventPreIme(keyEvent) } @Test fun forwardsInterceptMediaKey() { val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP) interactionEventHandler.interceptMediaKey(keyEvent) - verify(keyEventInteractor).interceptMediaKey(keyEvent) + verify(sysUIKeyEventHandler).interceptMediaKey(keyEvent) } companion object { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt index 189c9e25d9b0..a4a2ca0a6a21 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt @@ -48,7 +48,7 @@ import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.flags.SystemPropertiesHelper -import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor +import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.KeyguardUnlockAnimationController import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository @@ -253,7 +253,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { securityModel = Mockito.mock(KeyguardSecurityModel::class.java), ), BouncerLogger(logcatLogBuffer("BouncerLog")), - Mockito.mock(KeyEventInteractor::class.java), + Mockito.mock(SysUIKeyEventHandler::class.java), primaryBouncerInteractor, alternateBouncerInteractor, ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt index e71473681211..ae659f4d2676 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt @@ -131,11 +131,10 @@ class ClockRegistryTest : SysuiTestCase() { fun addClock( id: ClockId, - name: String, create: (ClockId) -> ClockController = ::failFactory, getThumbnail: (ClockId) -> Drawable? = ::failThumbnail ): FakeClockPlugin { - metadata.add(ClockMetadata(id, name)) + metadata.add(ClockMetadata(id)) createCallbacks[id] = create thumbnailCallbacks[id] = getThumbnail return this @@ -149,7 +148,7 @@ class ClockRegistryTest : SysuiTestCase() { scope = TestScope(dispatcher) fakeDefaultProvider = FakeClockPlugin() - .addClock(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME, { mockDefaultClock }, { mockThumbnail }) + .addClock(DEFAULT_CLOCK_ID, { mockDefaultClock }, { mockThumbnail }) whenever(mockContext.contentResolver).thenReturn(mockContentResolver) val captor = argumentCaptor<PluginListener<ClockProviderPlugin>>() @@ -183,13 +182,13 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun pluginRegistration_CorrectState() { val plugin1 = FakeClockPlugin() - .addClock("clock_1", "clock 1") - .addClock("clock_2", "clock 2") + .addClock("clock_1") + .addClock("clock_2") val lifecycle1 = FakeLifecycle("1", plugin1) val plugin2 = FakeClockPlugin() - .addClock("clock_3", "clock 3") - .addClock("clock_4", "clock 4") + .addClock("clock_3") + .addClock("clock_4") val lifecycle2 = FakeLifecycle("2", plugin2) pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1) @@ -198,11 +197,11 @@ class ClockRegistryTest : SysuiTestCase() { assertEquals( list.toSet(), setOf( - ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME), - ClockMetadata("clock_1", "clock 1"), - ClockMetadata("clock_2", "clock 2"), - ClockMetadata("clock_3", "clock 3"), - ClockMetadata("clock_4", "clock 4") + ClockMetadata(DEFAULT_CLOCK_ID), + ClockMetadata("clock_1"), + ClockMetadata("clock_2"), + ClockMetadata("clock_3"), + ClockMetadata("clock_4") ) ) } @@ -216,13 +215,13 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun clockIdConflict_ErrorWithoutCrash_unloadDuplicate() { val plugin1 = FakeClockPlugin() - .addClock("clock_1", "clock 1", { mockClock }, { mockThumbnail }) - .addClock("clock_2", "clock 2", { mockClock }, { mockThumbnail }) + .addClock("clock_1", { mockClock }, { mockThumbnail }) + .addClock("clock_2", { mockClock }, { mockThumbnail }) val lifecycle1 = spy(FakeLifecycle("1", plugin1)) val plugin2 = FakeClockPlugin() - .addClock("clock_1", "clock 1") - .addClock("clock_2", "clock 2") + .addClock("clock_1") + .addClock("clock_2") val lifecycle2 = spy(FakeLifecycle("2", plugin2)) pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1) @@ -231,9 +230,9 @@ class ClockRegistryTest : SysuiTestCase() { assertEquals( list.toSet(), setOf( - ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME), - ClockMetadata("clock_1", "clock 1"), - ClockMetadata("clock_2", "clock 2") + ClockMetadata(DEFAULT_CLOCK_ID), + ClockMetadata("clock_1"), + ClockMetadata("clock_2") ) ) @@ -248,13 +247,13 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun createCurrentClock_pluginConnected() { val plugin1 = FakeClockPlugin() - .addClock("clock_1", "clock 1") - .addClock("clock_2", "clock 2") + .addClock("clock_1") + .addClock("clock_2") val lifecycle1 = spy(FakeLifecycle("1", plugin1)) val plugin2 = FakeClockPlugin() - .addClock("clock_3", "clock 3", { mockClock }) - .addClock("clock_4", "clock 4") + .addClock("clock_3", { mockClock }) + .addClock("clock_4") val lifecycle2 = spy(FakeLifecycle("2", plugin2)) registry.applySettings(ClockSettings("clock_3", null)) @@ -268,13 +267,13 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun activeClockId_changeAfterPluginConnected() { val plugin1 = FakeClockPlugin() - .addClock("clock_1", "clock 1") - .addClock("clock_2", "clock 2") + .addClock("clock_1") + .addClock("clock_2") val lifecycle1 = spy(FakeLifecycle("1", plugin1)) val plugin2 = FakeClockPlugin() - .addClock("clock_3", "clock 3", { mockClock }) - .addClock("clock_4", "clock 4") + .addClock("clock_3", { mockClock }) + .addClock("clock_4") val lifecycle2 = spy(FakeLifecycle("2", plugin2)) registry.applySettings(ClockSettings("clock_3", null)) @@ -289,13 +288,13 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun createDefaultClock_pluginDisconnected() { val plugin1 = FakeClockPlugin() - .addClock("clock_1", "clock 1") - .addClock("clock_2", "clock 2") + .addClock("clock_1") + .addClock("clock_2") val lifecycle1 = spy(FakeLifecycle("1", plugin1)) val plugin2 = FakeClockPlugin() - .addClock("clock_3", "clock 3") - .addClock("clock_4", "clock 4") + .addClock("clock_3") + .addClock("clock_4") val lifecycle2 = spy(FakeLifecycle("2", plugin2)) registry.applySettings(ClockSettings("clock_3", null)) @@ -310,13 +309,13 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun pluginRemoved_clockAndListChanged() { val plugin1 = FakeClockPlugin() - .addClock("clock_1", "clock 1") - .addClock("clock_2", "clock 2") + .addClock("clock_1") + .addClock("clock_2") val lifecycle1 = spy(FakeLifecycle("1", plugin1)) val plugin2 = FakeClockPlugin() - .addClock("clock_3", "clock 3", { mockClock }) - .addClock("clock_4", "clock 4") + .addClock("clock_3", { mockClock }) + .addClock("clock_4") val lifecycle2 = spy(FakeLifecycle("2", plugin2)) var changeCallCount = 0 @@ -415,13 +414,13 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun pluginAddRemove_concurrentModification() { - val plugin1 = FakeClockPlugin().addClock("clock_1", "clock 1") + val plugin1 = FakeClockPlugin().addClock("clock_1") val lifecycle1 = FakeLifecycle("1", plugin1) - val plugin2 = FakeClockPlugin().addClock("clock_2", "clock 2") + val plugin2 = FakeClockPlugin().addClock("clock_2") val lifecycle2 = FakeLifecycle("2", plugin2) - val plugin3 = FakeClockPlugin().addClock("clock_3", "clock 3") + val plugin3 = FakeClockPlugin().addClock("clock_3") val lifecycle3 = FakeLifecycle("3", plugin3) - val plugin4 = FakeClockPlugin().addClock("clock_4", "clock 4") + val plugin4 = FakeClockPlugin().addClock("clock_4") val lifecycle4 = FakeLifecycle("4", plugin4) // Set the current clock to the final clock to load @@ -450,10 +449,10 @@ class ClockRegistryTest : SysuiTestCase() { // Verify all plugins were correctly loaded into the registry assertEquals(registry.getClocks().toSet(), setOf( - ClockMetadata("DEFAULT", "Default Clock"), - ClockMetadata("clock_2", "clock 2"), - ClockMetadata("clock_3", "clock 3"), - ClockMetadata("clock_4", "clock 4") + ClockMetadata("DEFAULT"), + ClockMetadata("clock_2"), + ClockMetadata("clock_3"), + ClockMetadata("clock_4") )) } @@ -527,8 +526,8 @@ class ClockRegistryTest : SysuiTestCase() { featureFlags.set(TRANSIT_CLOCK, flag) registry.isTransitClockEnabled = featureFlags.isEnabled(TRANSIT_CLOCK) val plugin = FakeClockPlugin() - .addClock("clock_1", "clock 1") - .addClock("DIGITAL_CLOCK_METRO", "metro clock") + .addClock("clock_1") + .addClock("DIGITAL_CLOCK_METRO") val lifecycle = FakeLifecycle("metro", plugin) pluginListener.onPluginLoaded(plugin, mockContext, lifecycle) @@ -536,17 +535,17 @@ class ClockRegistryTest : SysuiTestCase() { if (flag) { assertEquals( setOf( - ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME), - ClockMetadata("clock_1", "clock 1"), - ClockMetadata("DIGITAL_CLOCK_METRO", "metro clock") + ClockMetadata(DEFAULT_CLOCK_ID), + ClockMetadata("clock_1"), + ClockMetadata("DIGITAL_CLOCK_METRO") ), list.toSet() ) } else { assertEquals( setOf( - ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME), - ClockMetadata("clock_1", "clock 1") + ClockMetadata(DEFAULT_CLOCK_ID), + ClockMetadata("clock_1") ), list.toSet() ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt new file mode 100644 index 000000000000..2f8f3bb14ee5 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt @@ -0,0 +1,102 @@ +/* + * 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. + */ +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.statusbar.notification.data.repository + +import androidx.test.filters.SmallTest +import com.android.SysUITestModule +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.mockito.withArgCaptor +import com.google.common.truth.Truth.assertThat +import dagger.BindsInstance +import dagger.Component +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.mockito.Mockito.verify + +@SmallTest +class NotificationsKeyguardViewStateRepositoryTest : SysuiTestCase() { + + private val testComponent: TestComponent = + DaggerNotificationsKeyguardViewStateRepositoryTest_TestComponent.factory() + .create(test = this) + + @Test + fun areNotifsFullyHidden_reflectsWakeUpCoordinator() = + with(testComponent) { + testScope.runTest { + whenever(mockWakeUpCoordinator.notificationsFullyHidden).thenReturn(false) + val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden) + runCurrent() + + assertThat(notifsFullyHidden).isFalse() + + withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) } + .onFullyHiddenChanged(true) + runCurrent() + + assertThat(notifsFullyHidden).isTrue() + } + } + + @Test + fun isPulseExpanding_reflectsWakeUpCoordinator() = + with(testComponent) { + testScope.runTest { + whenever(mockWakeUpCoordinator.isPulseExpanding()).thenReturn(false) + val isPulseExpanding by collectLastValue(underTest.isPulseExpanding) + runCurrent() + + assertThat(isPulseExpanding).isFalse() + + withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) } + .onPulseExpansionChanged(true) + runCurrent() + + assertThat(isPulseExpanding).isTrue() + } + } + + @SysUISingleton + @Component( + modules = + [ + SysUITestModule::class, + ] + ) + interface TestComponent { + + val underTest: NotificationsKeyguardViewStateRepositoryImpl + + val mockWakeUpCoordinator: NotificationWakeUpCoordinator + val testScope: TestScope + + @Component.Factory + interface Factory { + fun create( + @BindsInstance test: SysuiTestCase, + ): TestComponent + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt new file mode 100644 index 000000000000..705a5a3f9792 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt @@ -0,0 +1,89 @@ +/* + * 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 com.android.systemui.statusbar.notification.domain.interactor + +import androidx.test.filters.SmallTest +import com.android.SysUITestModule +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardViewStateRepository +import com.google.common.truth.Truth.assertThat +import dagger.BindsInstance +import dagger.Component +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test + +@SmallTest +class NotificationsKeyguardInteractorTest : SysuiTestCase() { + + private val testComponent: TestComponent = + DaggerNotificationsKeyguardInteractorTest_TestComponent.factory().create(test = this) + + @Test + fun areNotifsFullyHidden_reflectsRepository() = + with(testComponent) { + testScope.runTest { + repository.setNotificationsFullyHidden(false) + val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden) + runCurrent() + + assertThat(notifsFullyHidden).isFalse() + + repository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(notifsFullyHidden).isTrue() + } + } + + @Test + fun isPulseExpanding_reflectsRepository() = + with(testComponent) { + testScope.runTest { + repository.setPulseExpanding(false) + val isPulseExpanding by collectLastValue(underTest.isPulseExpanding) + runCurrent() + + assertThat(isPulseExpanding).isFalse() + + repository.setPulseExpanding(true) + runCurrent() + + assertThat(isPulseExpanding).isTrue() + } + } + + @SysUISingleton + @Component( + modules = + [ + SysUITestModule::class, + ] + ) + interface TestComponent { + + val underTest: NotificationsKeyguardInteractor + + val repository: FakeNotificationsKeyguardViewStateRepository + val testScope: TestScope + + @Component.Factory + interface Factory { + fun create(@BindsInstance test: SysuiTestCase): TestComponent + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FooterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java index b120c4747cb9..f72142ffc6d7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FooterViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java @@ -11,10 +11,10 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ -package com.android.systemui.statusbar.notification.row; +package com.android.systemui.statusbar.notification.footer.ui.view; import static com.google.common.truth.Truth.assertThat; @@ -31,8 +31,8 @@ import android.widget.TextView; import androidx.test.filters.SmallTest; -import com.android.systemui.res.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.res.R; import org.junit.Before; import org.junit.Test; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt index 7caa5ccc5837..e57986ddfa18 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt @@ -26,9 +26,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FakeFeatureFlagsClassicModule import com.android.systemui.flags.Flags import com.android.systemui.statusbar.phone.DozeParameters -import com.android.systemui.statusbar.phone.NotificationIconContainer import com.android.systemui.user.domain.UserDomainLayerModule -import com.android.systemui.util.mockito.whenever import dagger.BindsInstance import dagger.Component import org.junit.Assert.assertFalse @@ -37,7 +35,6 @@ 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.MockitoAnnotations @SmallTest @@ -46,7 +43,6 @@ import org.mockito.MockitoAnnotations class NotificationIconAreaControllerViewBinderWrapperImplTest : SysuiTestCase() { @Mock private lateinit var dozeParams: DozeParameters - @Mock private lateinit var aodIcons: NotificationIconContainer private lateinit var testComponent: TestComponent private val underTest @@ -85,15 +81,6 @@ class NotificationIconAreaControllerViewBinderWrapperImplTest : SysuiTestCase() assertTrue(underTest.shouldShowLowPriorityIcons()) } - @Test - fun testAppearResetsTranslation() { - underTest.setupAodIcons(aodIcons) - whenever(dozeParams.shouldControlScreenOff()).thenReturn(false) - underTest.appearAodIcons() - verify(aodIcons).translationY = 0f - verify(aodIcons).alpha = 1.0f - } - @SysUISingleton @Component( modules = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt index 99c3b194a662..31efebbc5b60 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt @@ -25,6 +25,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule import com.android.systemui.coroutines.collectLastValue import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository import com.android.systemui.flags.FakeFeatureFlagsClassicModule import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository @@ -37,10 +38,13 @@ import com.android.systemui.keyguard.shared.model.TransitionStep 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.statusbar.notification.data.repository.FakeNotificationsKeyguardViewStateRepository import com.android.systemui.statusbar.phone.DozeParameters +import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository import com.android.systemui.user.domain.UserDomainLayerModule import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.ui.AnimatedValue import com.google.common.truth.Truth.assertThat import dagger.BindsInstance import dagger.Component @@ -59,19 +63,24 @@ import org.mockito.MockitoAnnotations class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { @Mock private lateinit var dozeParams: DozeParameters + @Mock private lateinit var screenOffAnimController: ScreenOffAnimationController private lateinit var testComponent: TestComponent - private val underTest + private val underTest: NotificationIconContainerAlwaysOnDisplayViewModel get() = testComponent.underTest - private val deviceProvisioningRepository + private val deviceEntryRepository: FakeDeviceEntryRepository + get() = testComponent.deviceEntryRepository + private val deviceProvisioningRepository: FakeDeviceProvisioningRepository get() = testComponent.deviceProvisioningRepository - private val keyguardRepository + private val keyguardRepository: FakeKeyguardRepository get() = testComponent.keyguardRepository - private val keyguardTransitionRepository + private val keyguardTransitionRepository: FakeKeyguardTransitionRepository get() = testComponent.keyguardTransitionRepository - private val powerRepository + private val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository + get() = testComponent.notifsKeyguardRepository + private val powerRepository: FakePowerRepository get() = testComponent.powerRepository - private val scope + private val scope: TestScope get() = testComponent.scope @Before @@ -84,12 +93,14 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { test = this, featureFlags = FakeFeatureFlagsClassicModule { - set(Flags.FACE_AUTH_REFACTOR, value = false) + setDefault(Flags.FACE_AUTH_REFACTOR) set(Flags.FULL_SCREEN_USER_SWITCHER, value = false) + setDefault(Flags.NEW_AOD_TRANSITION) }, mocks = TestMocksModule( dozeParameters = dozeParams, + screenOffAnimationController = screenOffAnimController, ), ) @@ -251,6 +262,204 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { assertThat(animationsEnabled).isFalse() } + @Test + fun isDozing_startAodTransition() = + scope.runTest { + val isDozing by collectLastValue(underTest.isDozing) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.AOD, + transitionState = TransitionState.STARTED, + ) + ) + runCurrent() + assertThat(isDozing).isEqualTo(AnimatedValue(true, isAnimating = true)) + } + + @Test + fun isDozing_startDozeTransition() = + scope.runTest { + val isDozing by collectLastValue(underTest.isDozing) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.DOZING, + transitionState = TransitionState.STARTED, + ) + ) + runCurrent() + assertThat(isDozing).isEqualTo(AnimatedValue(true, isAnimating = false)) + } + + @Test + fun isDozing_startDozeToAodTransition() = + scope.runTest { + val isDozing by collectLastValue(underTest.isDozing) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.DOZING, + to = KeyguardState.AOD, + transitionState = TransitionState.STARTED, + ) + ) + runCurrent() + assertThat(isDozing).isEqualTo(AnimatedValue(true, isAnimating = true)) + } + + @Test + fun isNotDozing_startAodToGoneTransition() = + scope.runTest { + val isDozing by collectLastValue(underTest.isDozing) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.AOD, + to = KeyguardState.GONE, + transitionState = TransitionState.STARTED, + ) + ) + runCurrent() + assertThat(isDozing).isEqualTo(AnimatedValue(false, isAnimating = true)) + } + + @Test + fun isDozing_stopAnimation() = + scope.runTest { + val isDozing by collectLastValue(underTest.isDozing) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.AOD, + to = KeyguardState.GONE, + transitionState = TransitionState.STARTED, + ) + ) + runCurrent() + + underTest.completeDozeAnimation() + runCurrent() + + assertThat(isDozing?.isAnimating).isEqualTo(false) + } + + @Test + fun isNotVisible_pulseExpanding() = + scope.runTest { + val isVisible by collectLastValue(underTest.isVisible) + notifsKeyguardRepository.setPulseExpanding(true) + runCurrent() + + assertThat(isVisible?.value).isFalse() + } + + @Test + fun isNotVisible_notOnKeyguard_dontShowAodIconsWhenShade() = + scope.runTest { + val isVisible by collectLastValue(underTest.isVisible) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + to = KeyguardState.GONE, + transitionState = TransitionState.FINISHED, + ) + ) + whenever(screenOffAnimController.shouldShowAodIconsWhenShade()).thenReturn(false) + runCurrent() + + assertThat(isVisible).isEqualTo(AnimatedValue(false, isAnimating = false)) + } + + @Test + fun isVisible_bypassEnabled() = + scope.runTest { + val isVisible by collectLastValue(underTest.isVisible) + deviceEntryRepository.setBypassEnabled(true) + runCurrent() + + assertThat(isVisible?.value).isTrue() + } + + @Test + fun isNotVisible_pulseExpanding_notBypassing() = + scope.runTest { + val isVisible by collectLastValue(underTest.isVisible) + notifsKeyguardRepository.setPulseExpanding(true) + deviceEntryRepository.setBypassEnabled(false) + runCurrent() + + assertThat(isVisible?.value).isEqualTo(false) + } + + @Test + fun isVisible_notifsFullyHidden_bypassEnabled() = + scope.runTest { + val isVisible by collectLastValue(underTest.isVisible) + runCurrent() + notifsKeyguardRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(true) + notifsKeyguardRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = true)) + } + + @Test + fun isVisible_notifsFullyHidden_bypassDisabled_aodDisabled() = + scope.runTest { + val isVisible by collectLastValue(underTest.isVisible) + notifsKeyguardRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParams.alwaysOn).thenReturn(false) + notifsKeyguardRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = false)) + } + + @Test + fun isVisible_notifsFullyHidden_bypassDisabled_displayNeedsBlanking() = + scope.runTest { + val isVisible by collectLastValue(underTest.isVisible) + notifsKeyguardRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParams.alwaysOn).thenReturn(true) + whenever(dozeParams.displayNeedsBlanking).thenReturn(true) + notifsKeyguardRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = false)) + } + + @Test + fun isVisible_notifsFullyHidden_bypassDisabled() = + scope.runTest { + val isVisible by collectLastValue(underTest.isVisible) + runCurrent() + notifsKeyguardRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParams.alwaysOn).thenReturn(true) + whenever(dozeParams.displayNeedsBlanking).thenReturn(false) + notifsKeyguardRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = true)) + } + + @Test + fun isVisible_stopAnimation() = + scope.runTest { + val isVisible by collectLastValue(underTest.isVisible) + notifsKeyguardRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParams.alwaysOn).thenReturn(true) + whenever(dozeParams.displayNeedsBlanking).thenReturn(false) + notifsKeyguardRepository.setNotificationsFullyHidden(true) + runCurrent() + + underTest.completeVisibilityAnimation() + runCurrent() + + assertThat(isVisible?.isAnimating).isEqualTo(false) + } + @SysUISingleton @Component( modules = @@ -264,9 +473,11 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { val underTest: NotificationIconContainerAlwaysOnDisplayViewModel + val deviceEntryRepository: FakeDeviceEntryRepository val deviceProvisioningRepository: FakeDeviceProvisioningRepository val keyguardRepository: FakeKeyguardRepository val keyguardTransitionRepository: FakeKeyguardTransitionRepository + val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository val powerRepository: FakePowerRepository val scope: TestScope diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt index d1518f7e0d08..e1e7f92265f0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt @@ -82,6 +82,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() { DaggerNotificationIconContainerStatusBarViewModelTest_TestComponent.factory() .create( test = this, + // Configurable bindings featureFlags = FakeFeatureFlagsClassicModule { set(Flags.FACE_AUTH_REFACTOR, value = false) @@ -248,6 +249,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() { modules = [ SysUITestModule::class, + // Real impls BiometricsDomainLayerModule::class, UserDomainLayerModule::class, ] diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java index c9b77c5372df..9c20e541e35f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java @@ -54,9 +54,9 @@ import android.widget.ImageView; import android.widget.TextView; import com.android.internal.statusbar.IStatusBarService; -import com.android.systemui.res.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; +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; @@ -132,7 +132,8 @@ public class FeedbackInfoTest extends SysuiTestCase { public void testBindNotification_SetsTextApplicationName() { when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name"); mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), - mMockNotificationRow, mAssistantFeedbackController); + mMockNotificationRow, mAssistantFeedbackController, mStatusBarService, + mNotificationGutsManager); final TextView textView = mFeedbackInfo.findViewById(R.id.pkg_name); assertTrue(textView.getText().toString().contains("App Name")); } @@ -143,7 +144,8 @@ public class FeedbackInfoTest extends SysuiTestCase { when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class))) .thenReturn(iconDrawable); mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), - mMockNotificationRow, mAssistantFeedbackController); + mMockNotificationRow, mAssistantFeedbackController, mStatusBarService, + mNotificationGutsManager); final ImageView iconView = mFeedbackInfo.findViewById(R.id.pkg_icon); assertEquals(iconDrawable, iconView.getDrawable()); } @@ -153,7 +155,7 @@ public class FeedbackInfoTest extends SysuiTestCase { when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class))) .thenReturn(STATUS_SILENCED); mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow, - mAssistantFeedbackController); + mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager); TextView prompt = mFeedbackInfo.findViewById(R.id.prompt); assertEquals("This notification was automatically demoted to Silent by the system. " + "Let the developer know your feedback. Was this correct?", @@ -165,7 +167,7 @@ public class FeedbackInfoTest extends SysuiTestCase { when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class))) .thenReturn(STATUS_PROMOTED); mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow, - mAssistantFeedbackController); + mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager); TextView prompt = mFeedbackInfo.findViewById(R.id.prompt); assertEquals("This notification was automatically ranked higher in your shade. " + "Let the developer know your feedback. Was this correct?", @@ -177,7 +179,7 @@ public class FeedbackInfoTest extends SysuiTestCase { when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class))) .thenReturn(STATUS_ALERTED); mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow, - mAssistantFeedbackController); + mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager); TextView prompt = mFeedbackInfo.findViewById(R.id.prompt); assertEquals("This notification was automatically promoted to Default by the system. " + "Let the developer know your feedback. Was this correct?", @@ -189,7 +191,7 @@ public class FeedbackInfoTest extends SysuiTestCase { when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class))) .thenReturn(STATUS_DEMOTED); mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow, - mAssistantFeedbackController); + mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager); TextView prompt = mFeedbackInfo.findViewById(R.id.prompt); assertEquals("This notification was automatically ranked lower in your shade. " + "Let the developer know your feedback. Was this correct?", @@ -199,7 +201,7 @@ public class FeedbackInfoTest extends SysuiTestCase { @Test public void testPositiveFeedback() { mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow, - mAssistantFeedbackController); + mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager); final View yes = mFeedbackInfo.findViewById(R.id.yes); yes.performClick(); @@ -216,7 +218,7 @@ public class FeedbackInfoTest extends SysuiTestCase { .thenReturn(true); mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow, - mAssistantFeedbackController); + mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager); final View no = mFeedbackInfo.findViewById(R.id.no); no.performClick(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index 1ab36b805ca6..8a730cfd7ddd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -195,6 +195,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { mWindowRootViewVisibilityInteractor, mNotificationLockscreenUserManager, mStatusBarStateController, + mBarService, mDeviceProvisionedController, mMetricsLogger, mHeadsUpManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 236bcb416573..a2be8b0e0be2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -65,12 +65,12 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.BouncerPanelExpansionCalculator; import com.android.systemui.ExpandHelper; -import com.android.systemui.res.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.res.R; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.transition.LargeScreenShadeInterpolator; import com.android.systemui.statusbar.EmptyShadeView; @@ -81,9 +81,9 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; +import com.android.systemui.statusbar.notification.footer.ui.view.FooterView; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.FooterView; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt index 93faa77bef5c..49906dca0344 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt @@ -5,18 +5,18 @@ import android.content.pm.PackageManager import android.widget.FrameLayout import androidx.test.filters.SmallTest import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.animation.ShadeInterpolation.getContentAlpha import com.android.systemui.dump.DumpManager +import com.android.systemui.res.R import com.android.systemui.shade.transition.LargeScreenShadeInterpolator import com.android.systemui.statusbar.EmptyShadeView import com.android.systemui.statusbar.NotificationShelf import com.android.systemui.statusbar.StatusBarState +import com.android.systemui.statusbar.notification.footer.ui.view.FooterView +import com.android.systemui.statusbar.notification.footer.ui.view.FooterView.FooterViewState import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView -import com.android.systemui.statusbar.notification.row.FooterView -import com.android.systemui.statusbar.notification.row.FooterView.FooterViewState import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import com.android.systemui.util.mockito.mock import com.google.common.truth.Expect diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt new file mode 100644 index 000000000000..aaf8d0761dce --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt @@ -0,0 +1,98 @@ +/* + * 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 com.android.systemui.util.ui + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class AnimatedValueTest : SysuiTestCase() { + + @Test + fun animatableEvent_updatesValue() = runTest { + val events = MutableSharedFlow<AnimatableEvent<Int>>() + val values = events.toAnimatedValueFlow(completionEvents = emptyFlow()) + val value by collectLastValue(values) + runCurrent() + + events.emit(AnimatableEvent(value = 1, startAnimating = false)) + + assertThat(value).isEqualTo(AnimatedValue(value = 1, isAnimating = false)) + } + + @Test + fun animatableEvent_startAnimation() = runTest { + val events = MutableSharedFlow<AnimatableEvent<Int>>() + val values = events.toAnimatedValueFlow(completionEvents = emptyFlow()) + val value by collectLastValue(values) + runCurrent() + + events.emit(AnimatableEvent(value = 1, startAnimating = true)) + + assertThat(value).isEqualTo(AnimatedValue(value = 1, isAnimating = true)) + } + + @Test + fun animatableEvent_startAnimation_alreadyAnimating() = runTest { + val events = MutableSharedFlow<AnimatableEvent<Int>>() + val values = events.toAnimatedValueFlow(completionEvents = emptyFlow()) + val value by collectLastValue(values) + runCurrent() + + events.emit(AnimatableEvent(value = 1, startAnimating = true)) + events.emit(AnimatableEvent(value = 2, startAnimating = true)) + + assertThat(value).isEqualTo(AnimatedValue(value = 2, isAnimating = true)) + } + + @Test + fun animatedValue_stopAnimating() = runTest { + val events = MutableSharedFlow<AnimatableEvent<Int>>() + val stopEvent = MutableSharedFlow<Unit>() + val values = events.toAnimatedValueFlow(completionEvents = stopEvent) + val value by collectLastValue(values) + runCurrent() + + events.emit(AnimatableEvent(value = 1, startAnimating = true)) + stopEvent.emit(Unit) + + assertThat(value).isEqualTo(AnimatedValue(value = 1, isAnimating = false)) + } + + @Test + fun animatedValue_stopAnimating_notAnimating() = runTest { + val events = MutableSharedFlow<AnimatableEvent<Int>>() + val stopEvent = MutableSharedFlow<Unit>() + val values = events.toAnimatedValueFlow(completionEvents = stopEvent) + values.launchIn(backgroundScope) + runCurrent() + + events.emit(AnimatableEvent(value = 1, startAnimating = false)) + + assertThat(stopEvent.subscriptionCount.value).isEqualTo(0) + } +} diff --git a/packages/SystemUI/tests/utils/src/android/animation/PlatformAnimatorIsolationRule.kt b/packages/SystemUI/tests/utils/src/android/animation/PlatformAnimatorIsolationRule.kt index 43a26f34ef2e..ca5e1d075856 100644 --- a/packages/SystemUI/tests/utils/src/android/animation/PlatformAnimatorIsolationRule.kt +++ b/packages/SystemUI/tests/utils/src/android/animation/PlatformAnimatorIsolationRule.kt @@ -41,7 +41,7 @@ class PlatformAnimatorIsolationRule : TestRule { private fun onError() = exceptionDeferrer.fail( "Test's animations are not isolated! " + - "Did you forget to add an AnimatorTestRule to your test class?" + "Did you forget to add an AnimatorTestRule as a @Rule?" ) fun throwDeferred() = exceptionDeferrer.throwDeferred() diff --git a/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt b/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt index 7a97029ca6b0..95335a639ea2 100644 --- a/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt +++ b/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt @@ -37,7 +37,7 @@ class AndroidXAnimatorIsolationRule : TestRule { private fun onError() = exceptionDeferrer.fail( "Test's animations are not isolated! " + - "Did you forget to add an AnimatorTestRule to your test class?" + "Did you forget to add an AnimatorTestRule as a @Rule?" ) fun throwDeferred() = exceptionDeferrer.throwDeferred() diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt index 813197b171ad..dc5fd953239d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt @@ -24,6 +24,7 @@ import com.android.systemui.settings.FakeSettingsModule import com.android.systemui.statusbar.policy.FakeConfigurationControllerModule import com.android.systemui.statusbar.policy.FakeSplitShadeStateControllerModule import com.android.systemui.util.concurrency.FakeExecutorModule +import com.android.systemui.util.time.FakeSystemClockModule import dagger.Module @Module( @@ -36,6 +37,7 @@ import dagger.Module FakeSceneModule::class, FakeSettingsModule::class, FakeSplitShadeStateControllerModule::class, + FakeSystemClockModule::class, FakeSystemUiDataLayerModule::class, FakeUiEventLoggerModule::class, ] diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java index d6632a3c5ea7..f7e0120d3843 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java @@ -15,8 +15,6 @@ */ package com.android.systemui; -import static com.android.systemui.animation.FakeDialogLaunchAnimatorKt.fakeDialogLaunchAnimator; - import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -37,19 +35,15 @@ import androidx.core.animation.AndroidXAnimatorIsolationRule; import androidx.test.InstrumentationRegistry; import androidx.test.uiautomator.UiDevice; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.FakeBroadcastDispatcher; import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger; import com.android.systemui.dump.DumpManager; import com.android.systemui.settings.UserTracker; -import com.android.systemui.statusbar.phone.SystemUIDialogManager; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; -import org.junit.ClassRule; import org.junit.Rule; import org.mockito.Mockito; @@ -69,8 +63,8 @@ public abstract class SysuiTestCase { private Handler mHandler; // set the lowest order so it's the outermost rule - @ClassRule(order = Integer.MIN_VALUE) - public static AndroidXAnimatorIsolationRule mAndroidXAnimatorIsolationRule = + @Rule(order = Integer.MIN_VALUE) + public AndroidXAnimatorIsolationRule mAndroidXAnimatorIsolationRule = new AndroidXAnimatorIsolationRule(); @Rule @@ -94,10 +88,7 @@ public abstract class SysuiTestCase { if (isRobolectricTest()) { mContext = mContext.createDefaultDisplayContext(); } - SystemUIInitializer initializer = new SystemUIInitializerImpl(mContext); - initializer.init(true); - mDependency = new TestableDependency(initializer.getSysUIComponent().createDependency()); - Dependency.setInstance(mDependency); + mDependency = SysuiTestDependencyKt.installSysuiTestDependency(mContext); mFakeBroadcastDispatcher = new FakeBroadcastDispatcher( mContext, mContext.getMainExecutor(), @@ -124,13 +115,6 @@ public abstract class SysuiTestCase { // reference and are never sent to the Context. This will also prevent a real // BroadcastDispatcher from actually registering receivers. mDependency.injectTestDependency(BroadcastDispatcher.class, mFakeBroadcastDispatcher); - mDependency.injectMockDependency(KeyguardUpdateMonitor.class); - - // Make sure that all tests on any SystemUIDialog does not crash because this dependency - // is missing (constructing the actual one would throw). - // TODO(b/219008720): Remove this. - mDependency.injectMockDependency(SystemUIDialogManager.class); - mDependency.injectTestDependency(DialogLaunchAnimator.class, fakeDialogLaunchAnimator()); } protected boolean shouldFailOnLeakedReceiver() { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt new file mode 100644 index 000000000000..c791f4f70920 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt @@ -0,0 +1,26 @@ +package com.android.systemui + +import android.annotation.SuppressLint +import android.content.Context +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.animation.DialogLaunchAnimator +import com.android.systemui.animation.fakeDialogLaunchAnimator +import com.android.systemui.statusbar.phone.SystemUIDialogManager + +@SuppressLint("VisibleForTests") +fun installSysuiTestDependency(context: Context): TestableDependency { + val initializer: SystemUIInitializer = SystemUIInitializerImpl(context) + initializer.init(true) + + val dependency = TestableDependency(initializer.sysUIComponent.createDependency()) + Dependency.setInstance(dependency) + + dependency.injectMockDependency(KeyguardUpdateMonitor::class.java) + + // Make sure that all tests on any SystemUIDialog does not crash because this dependency + // is missing (constructing the actual one would throw). + // TODO(b/219008720): Remove this. + dependency.injectMockDependency(SystemUIDialogManager::class.java) + dependency.injectTestDependency(DialogLaunchAnimator::class.java, fakeDialogLaunchAnimator()) + return dependency +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/FakeAuthenticationDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/FakeAuthenticationDataLayerModule.kt new file mode 100644 index 000000000000..8fa6695cab99 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/FakeAuthenticationDataLayerModule.kt @@ -0,0 +1,22 @@ +/* + * 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 com.android.systemui.authentication.data + +import com.android.systemui.authentication.data.repository.FakeAuthenticationRepositoryModule +import dagger.Module + +@Module(includes = [FakeAuthenticationRepositoryModule::class]) +object FakeAuthenticationDataLayerModule diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt index 4fc3e3f66e6d..ddfe79aedce6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt @@ -24,10 +24,17 @@ import com.android.systemui.authentication.data.model.AuthenticationMethodModel import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate import com.android.systemui.authentication.shared.model.AuthenticationResultModel import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository +import dagger.Binds +import dagger.Module +import dagger.Provides +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.currentTime class FakeAuthenticationRepository( private val deviceEntryRepository: FakeDeviceEntryRepository, @@ -201,3 +208,19 @@ class FakeAuthenticationRepository( } } } + +@OptIn(ExperimentalCoroutinesApi::class) +@Module(includes = [FakeAuthenticationRepositoryModule.Bindings::class]) +object FakeAuthenticationRepositoryModule { + @Provides + @SysUISingleton + fun provideFake( + deviceEntryRepository: FakeDeviceEntryRepository, + scope: TestScope, + ) = FakeAuthenticationRepository(deviceEntryRepository, currentTime = { scope.currentTime }) + + @Module + interface Bindings { + @Binds fun bindFake(fake: FakeAuthenticationRepository): AuthenticationRepository + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt index 29fb52aabd39..cffbf0271c29 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt @@ -15,6 +15,7 @@ */ package com.android.systemui.data +import com.android.systemui.authentication.data.FakeAuthenticationDataLayerModule import com.android.systemui.bouncer.data.repository.FakeBouncerDataLayerModule import com.android.systemui.common.ui.data.FakeCommonDataLayerModule import com.android.systemui.deviceentry.data.FakeDeviceEntryDataLayerModule @@ -29,6 +30,7 @@ import dagger.Module @Module( includes = [ + FakeAuthenticationDataLayerModule::class, FakeBouncerDataLayerModule::class, FakeCommonDataLayerModule::class, FakeDeviceEntryDataLayerModule::class, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryDataLayerModule.kt new file mode 100644 index 000000000000..f4feee19df65 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryDataLayerModule.kt @@ -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. + */ +package com.android.systemui.deviceentry.data.repository + +import dagger.Module + +@Module(includes = [FakeDeviceEntryRepositoryModule::class]) object FakeDeviceEntryDataLayerModule diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt index 26d95c0a0ea3..f0293489cb87 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt @@ -1,3 +1,18 @@ +/* + * 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 com.android.systemui.deviceentry.data.repository import com.android.systemui.dagger.SysUISingleton @@ -13,15 +28,13 @@ import kotlinx.coroutines.flow.asStateFlow class FakeDeviceEntryRepository @Inject constructor() : DeviceEntryRepository { private var isInsecureLockscreenEnabled = true - private var isBypassEnabled = false + + private val _isBypassEnabled = MutableStateFlow(false) + override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled private val _isUnlocked = MutableStateFlow(false) override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow() - override fun isBypassEnabled(): Boolean { - return isBypassEnabled - } - override suspend fun isInsecureLockscreenEnabled(): Boolean { return isInsecureLockscreenEnabled } @@ -35,7 +48,7 @@ class FakeDeviceEntryRepository @Inject constructor() : DeviceEntryRepository { } fun setBypassEnabled(isBypassEnabled: Boolean) { - this.isBypassEnabled = isBypassEnabled + _isBypassEnabled.value = isBypassEnabled } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/data/repository/FakeKeyEventRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/data/repository/FakeKeyEventRepository.kt new file mode 100644 index 000000000000..95b5316fbab5 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/data/repository/FakeKeyEventRepository.kt @@ -0,0 +1,30 @@ +/* + * Copyright 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 com.android.systemui.keyevent.data.repository + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow + +class FakeKeyEventRepository() : KeyEventRepository { + private val _isPowerButtonDown = MutableStateFlow(false) + override val isPowerButtonDown: Flow<Boolean> = _isPowerButtonDown.asStateFlow() + + fun setPowerButtonDown(isDown: Boolean) { + _isPowerButtonDown.value = isDown + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt index 822edfc7f6cd..e59f642071fb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.data import com.android.systemui.statusbar.disableflags.data.FakeStatusBarDisableFlagsDataLayerModule +import com.android.systemui.statusbar.notification.data.FakeStatusBarNotificationsDataLayerModule import com.android.systemui.statusbar.pipeline.data.FakeStatusBarPipelineDataLayerModule import com.android.systemui.statusbar.policy.data.FakeStatusBarPolicyDataLayerModule import dagger.Module @@ -24,6 +25,7 @@ import dagger.Module includes = [ FakeStatusBarDisableFlagsDataLayerModule::class, + FakeStatusBarNotificationsDataLayerModule::class, FakeStatusBarPipelineDataLayerModule::class, FakeStatusBarPolicyDataLayerModule::class, ] diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt new file mode 100644 index 000000000000..788e3aa9c41a --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt @@ -0,0 +1,22 @@ +/* + * 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 com.android.systemui.statusbar.notification.data + +import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardStateRepositoryModule +import dagger.Module + +@Module(includes = [FakeNotificationsKeyguardStateRepositoryModule::class]) +object FakeStatusBarNotificationsDataLayerModule diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeNotificationsKeyguardViewStateRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeNotificationsKeyguardViewStateRepository.kt new file mode 100644 index 000000000000..5d3cb4db9c7e --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeNotificationsKeyguardViewStateRepository.kt @@ -0,0 +1,49 @@ +/* + * 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 com.android.systemui.statusbar.notification.data.repository + +import com.android.systemui.dagger.SysUISingleton +import dagger.Binds +import dagger.Module +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow + +@SysUISingleton +class FakeNotificationsKeyguardViewStateRepository @Inject constructor() : + NotificationsKeyguardViewStateRepository { + private val _notificationsFullyHidden = MutableStateFlow(false) + override val areNotificationsFullyHidden: Flow<Boolean> = _notificationsFullyHidden + + private val _isPulseExpanding = MutableStateFlow(false) + override val isPulseExpanding: Flow<Boolean> = _isPulseExpanding + + fun setNotificationsFullyHidden(fullyHidden: Boolean) { + _notificationsFullyHidden.value = fullyHidden + } + + fun setPulseExpanding(expanding: Boolean) { + _isPulseExpanding.value = expanding + } +} + +@Module +interface FakeNotificationsKeyguardStateRepositoryModule { + @Binds + fun bindFake( + fake: FakeNotificationsKeyguardViewStateRepository + ): NotificationsKeyguardViewStateRepository +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt index 5de05c27ba2e..1f48d940f91c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt @@ -15,6 +15,7 @@ */ package com.android.systemui.util.concurrency +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.util.time.FakeSystemClock import dagger.Binds @@ -22,14 +23,12 @@ import dagger.Module import dagger.Provides import java.util.concurrent.Executor -@Module(includes = [FakeExecutorModule.Bindings::class]) -class FakeExecutorModule( - @get:Provides val clock: FakeSystemClock = FakeSystemClock(), -) { - @get:Provides val executor = FakeExecutor(clock) +@Module +interface FakeExecutorModule { + @Binds @Main @SysUISingleton fun bindMainExecutor(executor: FakeExecutor): Executor - @Module - interface Bindings { - @Binds @Main fun bindMainExecutor(executor: FakeExecutor): Executor + companion object { + @Provides + fun provideFake(clock: FakeSystemClock) = FakeExecutor(clock) } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockModule.kt new file mode 100644 index 000000000000..3e3d7cbb40b5 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockModule.kt @@ -0,0 +1,30 @@ +/* + * 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 com.android.systemui.util.time + +import com.android.systemui.dagger.SysUISingleton +import dagger.Binds +import dagger.Module +import dagger.Provides + +@Module +interface FakeSystemClockModule { + @Binds fun bindFake(fake: FakeSystemClock): SystemClock + + companion object { + @Provides @SysUISingleton fun providesFake() = FakeSystemClock() + } +} diff --git a/packages/WallpaperBackup/Android.bp b/packages/WallpaperBackup/Android.bp index 155dc1a68295..18f783146c72 100644 --- a/packages/WallpaperBackup/Android.bp +++ b/packages/WallpaperBackup/Android.bp @@ -49,7 +49,7 @@ android_test { "androidx.test.core", "androidx.test.rules", "mockito-target-minus-junit4", - "truth-prebuilt", + "truth", ], resource_dirs: ["test/res"], certificate: "platform", diff --git a/packages/overlays/tests/Android.bp b/packages/overlays/tests/Android.bp index b781602399a3..0244c0fe0533 100644 --- a/packages/overlays/tests/Android.bp +++ b/packages/overlays/tests/Android.bp @@ -34,7 +34,7 @@ android_test { "androidx.test.rules", "androidx.test.espresso.core", "mockito-target-minus-junit4", - "truth-prebuilt", + "truth", ], dxflags: ["--multi-dex"], } diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 7e09b5ea9fa5..258820a5a03c 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -24,6 +24,7 @@ import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -1660,8 +1661,21 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku synchronized (mLock) { ensureGroupStateLoadedLocked(userId); + final String pkg = componentName.getPackageName(); + final ProviderId id; + if (!mPackageManagerInternal.isSameApp(pkg, callingUid, userId)) { + // If the calling process is requesting to pin appwidgets from another process, + // check if the calling process has the necessary permission. + if (!injectHasAccessWidgetsPermission(Binder.getCallingPid(), callingUid)) { + return false; + } + id = new ProviderId(mPackageManagerInternal.getPackageUid( + pkg, 0 /* flags */, userId), componentName); + } else { + id = new ProviderId(callingUid, componentName); + } // Look for the widget associated with the caller. - Provider provider = lookupProviderLocked(new ProviderId(callingUid, componentName)); + Provider provider = lookupProviderLocked(id); if (provider == null || provider.zombie) { return false; } @@ -1675,6 +1689,14 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku .requestPinAppWidget(callingPackage, info, extras, resultSender, userId); } + /** + * Returns true if the caller has the proper permission to access app widgets. + */ + private boolean injectHasAccessWidgetsPermission(int callingPid, int callingUid) { + return mContext.checkPermission(Manifest.permission.CLEAR_APP_USER_DATA, + callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; + } + @Override public ParceledListSlice<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter, int profileId, String packageName) { @@ -4131,7 +4153,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku return false; } - @GuardedBy("mLock") + @GuardedBy("AppWidgetServiceImpl.mLock") public AppWidgetProviderInfo getInfoLocked(Context context) { if (!mInfoParsed) { // parse @@ -4159,18 +4181,18 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku * be completely parsed and only contain placeHolder information like * {@link AppWidgetProviderInfo#providerInfo} */ - @GuardedBy("mLock") + @GuardedBy("AppWidgetServiceImpl.mLock") public AppWidgetProviderInfo getPartialInfoLocked() { return info; } - @GuardedBy("mLock") + @GuardedBy("AppWidgetServiceImpl.mLock") public void setPartialInfoLocked(AppWidgetProviderInfo info) { this.info = info; mInfoParsed = false; } - @GuardedBy("mLock") + @GuardedBy("AppWidgetServiceImpl.mLock") public void setInfoLocked(AppWidgetProviderInfo info) { this.info = info; mInfoParsed = true; diff --git a/services/autofill/Android.bp b/services/autofill/Android.bp index d43a219e6205..eb23f2f9b435 100644 --- a/services/autofill/Android.bp +++ b/services/autofill/Android.bp @@ -19,19 +19,4 @@ java_library_static { defaults: ["platform_service_defaults"], srcs: [":services.autofill-sources"], libs: ["services.core"], - static_libs: ["autofill_flags_java_lib"], -} - -aconfig_declarations { - name: "autofill_flags", - package: "android.service.autofill", - srcs: [ - "bugfixes.aconfig", - "features.aconfig", - ], -} - -java_aconfig_library { - name: "autofill_flags_java_lib", - aconfig_declarations: "autofill_flags", } diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig index 123b65c039ba..b37bbd6ea27f 100644 --- a/services/autofill/bugfixes.aconfig +++ b/services/autofill/bugfixes.aconfig @@ -8,6 +8,13 @@ flag { } flag { + name: "fill_fields_from_current_session_only" + namespace: "autofill" + description: "Only fill autofill fields that are part of the current session." + bug: "270722825" +} + +flag { name: "relayout" namespace: "autofill" description: "Mitigation for relayout issue" diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index c7b53c55d89b..3e134992c763 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -58,6 +58,7 @@ import android.os.UserManager; import android.provider.DeviceConfig; import android.provider.Settings; import android.service.autofill.FillEventHistory; +import android.service.autofill.Flags; import android.service.autofill.UserData; import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; @@ -226,6 +227,9 @@ public final class AutofillManagerService @GuardedBy("mFlagLock") private int mMaxInputLengthForAutofill; + @GuardedBy("mFlagLock") + private boolean mIsFillFieldsFromCurrentSessionOnly; + // Default flag values for Autofill PCC private static final String DEFAULT_PCC_FEATURE_PROVIDER_HINTS = ""; @@ -701,6 +705,7 @@ public final class AutofillManagerService DeviceConfig.NAMESPACE_AUTOFILL, AutofillFeatureFlags.DEVICE_CONFIG_MAX_INPUT_LENGTH_FOR_AUTOFILL, AutofillFeatureFlags.DEFAULT_MAX_INPUT_LENGTH_FOR_AUTOFILL); + mIsFillFieldsFromCurrentSessionOnly = Flags.fillFieldsFromCurrentSessionOnly(); if (verbose) { Slog.v(mTag, "setDeviceConfigProperties() for PCC: " + "mPccClassificationEnabled=" + mPccClassificationEnabled @@ -1004,6 +1009,15 @@ public final class AutofillManagerService } } + /** + * Return if autofill should only fill in fields from current session. + */ + public boolean getIsFillFieldsFromCurrentSessionOnly() { + synchronized (mFlagLock) { + return mIsFillFieldsFromCurrentSessionOnly; + } + } + @Nullable @VisibleForTesting static Map<String, String[]> getAllowedCompatModePackages(String setting) { diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 0220deca18c1..ae1487775b74 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -2437,7 +2437,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + id + " destroyed"); return; } - fillInIntent = createAuthFillInIntentLocked(requestId, extras); + fillInIntent = createAuthFillInIntentLocked(requestId, extras, /* authExtras= */ null); if (fillInIntent == null) { forceRemoveFromServiceLocked(); return; @@ -5558,7 +5558,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mPresentationStatsEventLogger.maybeSetAuthenticationType( AUTHENTICATION_TYPE_DATASET_AUTHENTICATION); setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false); - final Intent fillInIntent = createAuthFillInIntentLocked(requestId, mClientState); + final Intent fillInIntent = createAuthFillInIntentLocked(requestId, mClientState, + dataset.getAuthenticationExtras()); if (fillInIntent == null) { forceRemoveFromServiceLocked(); return; @@ -5574,7 +5575,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // TODO: this should never be null, but we got at least one occurrence, probably due to a race. @GuardedBy("mLock") @Nullable - private Intent createAuthFillInIntentLocked(int requestId, Bundle extras) { + private Intent createAuthFillInIntentLocked(int requestId, Bundle extras, + @Nullable Bundle authExtras) { final Intent fillInIntent = new Intent(); final FillContext context = getFillContextByRequestIdLocked(requestId); @@ -5591,6 +5593,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } fillInIntent.putExtra(AutofillManager.EXTRA_ASSIST_STRUCTURE, context.getStructure()); fillInIntent.putExtra(AutofillManager.EXTRA_CLIENT_STATE, extras); + if (authExtras != null) { + fillInIntent.putExtra(AutofillManager.EXTRA_AUTH_STATE, authExtras); + } return fillInIntent; } @@ -6137,9 +6142,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState continue; } final AutofillId viewId = dataset.getFieldIds().get(i); + final ViewState viewState = mViewStates.get(viewId); + if (mService.getMaster().getIsFillFieldsFromCurrentSessionOnly() + && viewState != null && viewState.id.getSessionId() != id) { + if (sVerbose) { + Slog.v(TAG, "Skipping filling view: " + + viewId + " as it isn't part of the current session: " + id); + } + continue; + } ids.add(viewId); values.add(dataset.getFieldValues().get(i)); - final ViewState viewState = mViewStates.get(viewId); if (viewState != null && (viewState.getState() & ViewState.STATE_WAITING_DATASET_AUTH) != 0) { if (sVerbose) { diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java index cfe56e910b8a..5cb100a1bfa5 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java @@ -38,6 +38,7 @@ import android.companion.virtual.VirtualDeviceManager; import android.companion.virtual.VirtualDeviceParams; import android.companion.virtual.flags.Flags; import android.companion.virtual.sensor.VirtualSensor; +import android.companion.virtualnative.IVirtualDeviceManagerNative; import android.content.AttributionSource; import android.content.Context; import android.content.Intent; @@ -88,8 +89,11 @@ public class VirtualDeviceManagerService extends SystemService { private static final String TAG = "VirtualDeviceManagerService"; + private static final String VIRTUAL_DEVICE_NATIVE_SERVICE = "virtualdevice_native"; + private final Object mVirtualDeviceManagerLock = new Object(); private final VirtualDeviceManagerImpl mImpl; + private final VirtualDeviceManagerNativeImpl mNativeImpl; private final VirtualDeviceManagerInternal mLocalService; private VirtualDeviceLog mVirtualDeviceLog = new VirtualDeviceLog(getContext()); private final Handler mHandler = new Handler(Looper.getMainLooper()); @@ -125,6 +129,7 @@ public class VirtualDeviceManagerService extends SystemService { public VirtualDeviceManagerService(Context context) { super(context); mImpl = new VirtualDeviceManagerImpl(); + mNativeImpl = Flags.enableNativeVdm() ? new VirtualDeviceManagerNativeImpl() : null; mLocalService = new LocalService(); } @@ -155,6 +160,9 @@ public class VirtualDeviceManagerService extends SystemService { @Override public void onStart() { publishBinderService(Context.VIRTUAL_DEVICE_SERVICE, mImpl); + if (Flags.enableNativeVdm()) { + publishBinderService(VIRTUAL_DEVICE_NATIVE_SERVICE, mNativeImpl); + } publishLocalService(VirtualDeviceManagerInternal.class, mLocalService); ActivityTaskManagerInternal activityTaskManagerInternal = getLocalService( ActivityTaskManagerInternal.class); @@ -590,6 +598,19 @@ public class VirtualDeviceManagerService extends SystemService { } } + final class VirtualDeviceManagerNativeImpl extends IVirtualDeviceManagerNative.Stub { + @Override // Binder call + public int[] getDeviceIdsForUid(int uid) { + return mLocalService + .getDeviceIdsForUid(uid).stream().mapToInt(Integer::intValue).toArray(); + } + + @Override // Binder call + public int getDevicePolicy(int deviceId, int policyType) { + return mImpl.getDevicePolicy(deviceId, policyType); + } + } + private final class LocalService extends VirtualDeviceManagerInternal { @GuardedBy("mVirtualDeviceManagerLock") private final ArrayList<VirtualDisplayListener> diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index cd879083927f..8df54569cccd 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -1428,6 +1428,12 @@ public abstract class PackageManagerInternal { @UserIdInt int userId); /** + * Sends the PACKAGE_RESTARTED broadcast on the package manager handler thread. + */ + public abstract void sendPackageRestartedBroadcast(@NonNull String packageName, + int uid, @Intent.Flags int flags); + + /** * Return a list of all historical install sessions for the given user. */ public abstract ParceledListSlice<PackageInstaller.SessionInfo> getHistoricalSessions( diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 330742a2d748..5fb889a23fc5 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -5023,7 +5023,7 @@ public class AccountManagerService p.setDataPosition(0); Bundle simulateBundle = p.readBundle(); p.recycle(); - Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT); + Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class); if (intent != null && intent.getClass() != Intent.class) { return false; } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index d3ce47c56e49..19879db1d22e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4160,26 +4160,34 @@ public class ActivityManagerService extends IActivityManager.Stub @GuardedBy("this") private void finishForceStopPackageLocked(final String packageName, int uid) { - Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED, - Uri.fromParts("package", packageName, null)); + int flags = 0; if (!mProcessesReady) { - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY - | Intent.FLAG_RECEIVER_FOREGROUND); - } - final int userId = UserHandle.getUserId(uid); - final int[] broadcastAllowList = - getPackageManagerInternal().getVisibilityAllowList(packageName, userId); - intent.putExtra(Intent.EXTRA_UID, uid); - intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); - broadcastIntentLocked(null /* callerApp */, null /* callerPackage */, - null /* callerFeatureId */, intent, null /* resolvedType */, - null /* resultToApp */, null /* resultTo */, - 0 /* resultCode */, null /* resultData */, null /* resultExtras */, - null /* requiredPermissions */, null /* excludedPermissions */, - null /* excludedPackages */, OP_NONE, null /* bOptions */, false /* ordered */, - false /* sticky */, MY_PID, SYSTEM_UID, Binder.getCallingUid(), - Binder.getCallingPid(), userId, BackgroundStartPrivileges.NONE, - broadcastAllowList, null /* filterExtrasForReceiver */); + flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY + | Intent.FLAG_RECEIVER_FOREGROUND; + } + if (android.content.pm.Flags.stayStopped()) { + // Sent async using the PM handler, to maintain ordering with PACKAGE_UNSTOPPED + mPackageManagerInt.sendPackageRestartedBroadcast(packageName, + uid, flags); + } else { + Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED, + Uri.fromParts("package", packageName, null)); + intent.addFlags(flags); + final int userId = UserHandle.getUserId(uid); + final int[] broadcastAllowList = + getPackageManagerInternal().getVisibilityAllowList(packageName, userId); + intent.putExtra(Intent.EXTRA_UID, uid); + intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + broadcastIntentLocked(null /* callerApp */, null /* callerPackage */, + null /* callerFeatureId */, intent, null /* resolvedType */, + null /* resultToApp */, null /* resultTo */, + 0 /* resultCode */, null /* resultData */, null /* resultExtras */, + null /* requiredPermissions */, null /* excludedPermissions */, + null /* excludedPackages */, OP_NONE, null /* bOptions */, false /* ordered */, + false /* sticky */, MY_PID, SYSTEM_UID, Binder.getCallingUid(), + Binder.getCallingPid(), userId, BackgroundStartPrivileges.NONE, + broadcastAllowList, null /* filterExtrasForReceiver */); + } } private void cleanupDisabledPackageComponentsLocked( diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java index 928b5d8f3ca7..3cf4332349d7 100644 --- a/services/core/java/com/android/server/am/AppProfiler.java +++ b/services/core/java/com/android/server/am/AppProfiler.java @@ -1205,6 +1205,8 @@ public class AppProfiler { trackerMemFactor = mService.mProcessStats.getMemFactorLocked(); } + mLastMemoryLevel = memFactor; + mLastNumProcesses = mService.mProcessList.getLruSizeLOSP(); if (mService.mConstants.USE_MODERN_TRIM) { // Modern trim is not sent based on lowmem state // Dispatch UI_HIDDEN to processes that need it @@ -1235,8 +1237,6 @@ public class AppProfiler { return false; } - mLastMemoryLevel = memFactor; - mLastNumProcesses = mService.mProcessList.getLruSizeLOSP(); if (memFactor != ADJ_MEM_FACTOR_NORMAL) { if (mLowRamStartTime == 0) { mLowRamStartTime = now; diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index d8a269598bdc..3771c05a294e 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -1255,11 +1255,10 @@ class ProcessRecord implements WindowProcessListener { killProcessGroup = true; } if (killProcessGroup) { - if (async) { - ProcessList.killProcessGroup(uid, mPid); - } else { + if (!async) { Process.sendSignalToProcessGroup(uid, mPid, OsConstants.SIGKILL); } + ProcessList.killProcessGroup(uid, mPid); } } diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 816043e65544..1ba1f55af71b 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -137,9 +137,11 @@ public class SettingsToPropertiesMapper { "core_graphics", "haptics", "hardware_backed_security_mainline", + "input", "machine_learning", "mainline_sdk", "media_audio", + "media_drm", "media_solutions", "nfc", "pixel_audio_android", diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java index f74b45cbdb0e..e42b66472cbe 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java @@ -875,6 +875,10 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi public void simulateVhalFingerDown(int userId, int sensorId) { Slog.d(getTag(), "Simulate virtual HAL finger down event"); final AidlSession session = mFingerprintSensors.get(sensorId).getSessionForUser(userId); + if (session == null) { + Slog.e(getTag(), "no existing hal session found - aborting"); + return; + } final PointerContext pc = new PointerContext(); try { session.getSession().onPointerDownWithContext(pc); diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index 9e92c8d7342d..cfbe0c69b320 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -60,6 +60,9 @@ import com.android.server.display.config.LuxThrottling; import com.android.server.display.config.NitsMap; import com.android.server.display.config.NonNegativeFloatToFloatPoint; import com.android.server.display.config.Point; +import com.android.server.display.config.PowerThrottlingConfig; +import com.android.server.display.config.PowerThrottlingMap; +import com.android.server.display.config.PowerThrottlingPoint; import com.android.server.display.config.PredefinedBrightnessLimitNames; import com.android.server.display.config.RefreshRateConfigs; import com.android.server.display.config.RefreshRateRange; @@ -139,6 +142,30 @@ import javax.xml.datatype.DatatypeConfigurationException; * </screenBrightnessMap> * * <screenBrightnessDefault>0.65</screenBrightnessDefault> + * <powerThrottlingConfig> + * <brightnessLowestCapAllowed>0.1</brightnessLowestCapAllowed> + * <pollingWindowMillis>15</pollingWindowMillis> + * <powerThrottlingMap> + * <powerThrottlingPoint> + * <thermalStatus>severe</thermalStatus> + * <powerQuotaMilliWatts>200.6</powerQuotaMilliWatts> + * </powerThrottlingPoint> + * <powerThrottlingPoint> + * <thermalStatus>critical</thermalStatus> + * <powerQuotaMilliWatts>300</powerQuotaMilliWatts> + * </powerThrottlingPoint> + * </powerThrottlingMap> + * <powerThrottlingMap id="id_2"> // optional attribute, leave blank for default + * <powerThrottlingPoint> + * <thermalStatus>moderate</thermalStatus> + * <powerQuotaMilliWatts>400</powerQuotaMilliWatts> + * </powerThrottlingPoint> + * <powerThrottlingPoint> + * <thermalStatus>severe</thermalStatus> + * <powerQuotaMilliWatts>250</powerQuotaMilliWatts> + * </powerThrottlingPoint> + * </powerThrottlingMap> + * </powerThrottlingConfig> * * <thermalThrottling> * <brightnessThrottlingMap> @@ -669,6 +696,8 @@ public class DisplayDeviceConfig { private List<String> mQuirks; private boolean mIsHighBrightnessModeEnabled = false; private HighBrightnessModeData mHbmData; + @Nullable + private PowerThrottlingConfigData mPowerThrottlingConfigData; private DensityMapping mDensityMapping; private String mLoadedFrom = null; private Spline mSdrToHdrRatioSpline; @@ -781,6 +810,9 @@ public class DisplayDeviceConfig { private final HashMap<String, ThermalBrightnessThrottlingData> mThermalBrightnessThrottlingDataMapByThrottlingId = new HashMap<>(); + private final HashMap<String, PowerThrottlingData> + mPowerThrottlingDataMapByThrottlingId = new HashMap<>(); + private final Map<String, SparseArray<SurfaceControl.RefreshRateRange>> mRefreshRateThrottlingMap = new HashMap<>(); @@ -1458,6 +1490,14 @@ public class DisplayDeviceConfig { return hbmData; } + /** + * @return Power throttling configuration data for the display. + */ + @Nullable + public PowerThrottlingConfigData getPowerThrottlingConfigData() { + return mPowerThrottlingConfigData; + } + @NonNull public Map<BrightnessLimitMapType, Map<Float, Float>> getLuxThrottlingData() { return mLuxThrottlingData; @@ -1491,6 +1531,14 @@ public class DisplayDeviceConfig { } /** + * @return power throttling configuration data for this display, for each throttling id. + **/ + public HashMap<String, PowerThrottlingData> + getPowerThrottlingDataMapByThrottlingId() { + return mPowerThrottlingDataMapByThrottlingId; + } + + /** * @return Auto brightness darkening light debounce */ public long getAutoBrightnessDarkeningLightDebounce() { @@ -1702,6 +1750,9 @@ public class DisplayDeviceConfig { + ", mThermalBrightnessThrottlingDataMapByThrottlingId=" + mThermalBrightnessThrottlingDataMapByThrottlingId + "\n" + + ", mPowerThrottlingDataMapByThrottlingId=" + + mPowerThrottlingDataMapByThrottlingId + + "\n" + "mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease + ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease @@ -1853,6 +1904,7 @@ public class DisplayDeviceConfig { loadBrightnessConstraintsFromConfigXml(); loadBrightnessMap(config); loadThermalThrottlingConfig(config); + loadPowerThrottlingConfigData(config); loadHighBrightnessModeData(config); loadLuxThrottling(config); loadQuirks(config); @@ -2171,6 +2223,59 @@ public class DisplayDeviceConfig { } } + private boolean loadPowerThrottlingMaps(PowerThrottlingConfig throttlingConfig) { + final List<PowerThrottlingMap> maps = throttlingConfig.getPowerThrottlingMap(); + if (maps == null || maps.isEmpty()) { + Slog.i(TAG, "No power throttling map found"); + return false; + } + + for (PowerThrottlingMap map : maps) { + final List<PowerThrottlingPoint> points = map.getPowerThrottlingPoint(); + // At least 1 point is guaranteed by the display device config schema + List<PowerThrottlingData.ThrottlingLevel> throttlingLevels = + new ArrayList<>(points.size()); + + boolean badConfig = false; + for (PowerThrottlingPoint point : points) { + ThermalStatus status = point.getThermalStatus(); + if (!thermalStatusIsValid(status)) { + badConfig = true; + break; + } + + throttlingLevels.add(new PowerThrottlingData.ThrottlingLevel( + convertThermalStatus(status), + point.getPowerQuotaMilliWatts().floatValue())); + } + + if (!badConfig) { + String id = map.getId() == null ? DEFAULT_ID : map.getId(); + if (mPowerThrottlingDataMapByThrottlingId.containsKey(id)) { + throw new RuntimeException("Power throttling data with ID " + id + + " already exists"); + } + mPowerThrottlingDataMapByThrottlingId.put(id, + PowerThrottlingData.create(throttlingLevels)); + } + } + return true; + } + + private void loadPowerThrottlingConfigData(DisplayConfiguration config) { + final PowerThrottlingConfig powerThrottlingCfg = config.getPowerThrottlingConfig(); + if (powerThrottlingCfg == null) { + return; + } + if (!loadPowerThrottlingMaps(powerThrottlingCfg)) { + return; + } + float lowestBrightnessCap = powerThrottlingCfg.getBrightnessLowestCapAllowed().floatValue(); + int pollingWindowMillis = powerThrottlingCfg.getPollingWindowMillis().intValue(); + mPowerThrottlingConfigData = new PowerThrottlingConfigData(lowestBrightnessCap, + pollingWindowMillis); + } + private void loadRefreshRateSetting(DisplayConfiguration config) { final RefreshRateConfigs refreshRateConfigs = (config == null) ? null : config.getRefreshRate(); @@ -3379,6 +3484,148 @@ public class DisplayDeviceConfig { } /** + * Container for Power throttling configuration data. + * TODO(b/302814899): extract to separate class. + */ + public static class PowerThrottlingConfigData { + /** Lowest brightness cap allowed for this device. */ + public final float brightnessLowestCapAllowed; + /** Time window for polling power in seconds. */ + public final int pollingWindowMillis; + public PowerThrottlingConfigData(float brightnessLowestCapAllowed, + int pollingWindowMillis) { + this.brightnessLowestCapAllowed = brightnessLowestCapAllowed; + this.pollingWindowMillis = pollingWindowMillis; + } + + @Override + public String toString() { + return "PowerThrottlingConfigData{" + + "brightnessLowestCapAllowed: " + + brightnessLowestCapAllowed + + ", pollingWindowMillis: " + pollingWindowMillis + + "} "; + } + } + + /** + * Container for power throttling data. + * TODO(b/302814899): extract to separate class and unify with ThermalBrightnessThrottlingData. + */ + public static class PowerThrottlingData { + public List<ThrottlingLevel> throttlingLevels; + + /** + * thermal status to power quota mapping. + */ + public static class ThrottlingLevel { + public @PowerManager.ThermalStatus int thermalStatus; + public float powerQuotaMilliWatts; + + public ThrottlingLevel( + @PowerManager.ThermalStatus int thermalStatus, float powerQuotaMilliWatts) { + this.thermalStatus = thermalStatus; + this.powerQuotaMilliWatts = powerQuotaMilliWatts; + } + + @Override + public String toString() { + return "[" + thermalStatus + "," + powerQuotaMilliWatts + "]"; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ThrottlingLevel)) { + return false; + } + ThrottlingLevel otherThrottlingLevel = (ThrottlingLevel) obj; + + return otherThrottlingLevel.thermalStatus == this.thermalStatus + && otherThrottlingLevel.powerQuotaMilliWatts == this.powerQuotaMilliWatts; + } + + @Override + public int hashCode() { + int result = 1; + result = 31 * result + thermalStatus; + result = 31 * result + Float.hashCode(powerQuotaMilliWatts); + return result; + } + } + + + /** + * Creates multiple temperature based throttling levels of power quota. + */ + public static PowerThrottlingData create( + List<ThrottlingLevel> throttlingLevels) { + if (throttlingLevels == null || throttlingLevels.size() == 0) { + Slog.e(TAG, "PowerThrottlingData received null or empty throttling levels"); + return null; + } + + ThrottlingLevel prevLevel = throttlingLevels.get(0); + final int numLevels = throttlingLevels.size(); + for (int i = 1; i < numLevels; i++) { + ThrottlingLevel thisLevel = throttlingLevels.get(i); + + if (thisLevel.thermalStatus <= prevLevel.thermalStatus) { + Slog.e(TAG, "powerThrottlingMap must be strictly increasing, ignoring " + + "configuration. ThermalStatus " + thisLevel.thermalStatus + " <= " + + prevLevel.thermalStatus); + return null; + } + + if (thisLevel.powerQuotaMilliWatts >= prevLevel.powerQuotaMilliWatts) { + Slog.e(TAG, "powerThrottlingMap must be strictly decreasing, ignoring " + + "configuration. powerQuotaMilliWatts " + + thisLevel.powerQuotaMilliWatts + " >= " + + prevLevel.powerQuotaMilliWatts); + return null; + } + + prevLevel = thisLevel; + } + return new PowerThrottlingData(throttlingLevels); + } + + @Override + public String toString() { + return "PowerThrottlingData{" + + "throttlingLevels:" + throttlingLevels + + "} "; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof PowerThrottlingData)) { + return false; + } + + PowerThrottlingData otherData = (PowerThrottlingData) obj; + return throttlingLevels.equals(otherData.throttlingLevels); + } + + @Override + public int hashCode() { + return throttlingLevels.hashCode(); + } + + @VisibleForTesting + PowerThrottlingData(List<ThrottlingLevel> inLevels) { + throttlingLevels = new ArrayList<>(inLevels.size()); + for (ThrottlingLevel level : inLevels) { + throttlingLevels.add(new ThrottlingLevel(level.thermalStatus, + level.powerQuotaMilliWatts)); + } + } + } + + /** * Container for brightness throttling data. */ public static class ThermalBrightnessThrottlingData { diff --git a/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java b/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java index 652e6cfd67be..39f0b13f716a 100644 --- a/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java +++ b/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java @@ -105,16 +105,21 @@ public class HdrClamper { public void resetHdrConfig(HdrBrightnessData data, int width, int height, float minimumHdrPercentOfScreen, IBinder displayToken) { mHdrBrightnessData = data; - mHdrListener.mHdrMinPixels = (float) (width * height) * minimumHdrPercentOfScreen; + mHdrListener.mHdrMinPixels = minimumHdrPercentOfScreen <= 0 ? -1 + : (float) (width * height) * minimumHdrPercentOfScreen; if (displayToken != mRegisteredDisplayToken) { // token changed, resubscribe if (mRegisteredDisplayToken != null) { // previous token not null, unsubscribe mHdrListener.unregister(mRegisteredDisplayToken); mHdrVisible = false; + mRegisteredDisplayToken = null; } - if (displayToken != null) { // new token not null, subscribe + // new token not null and hdr min % of the screen is set, subscribe. + // e.g. for virtual display, HBM data will be missing and HdrListener + // should not be registered + if (displayToken != null && mHdrListener.mHdrMinPixels > 0) { mHdrListener.register(displayToken); + mRegisteredDisplayToken = displayToken; } - mRegisteredDisplayToken = displayToken; } recalculateBrightnessCap(data, mAmbientLux, mHdrVisible); } 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 d5382cb99d22..f7b98691f3d7 100644 --- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java @@ -55,6 +55,10 @@ public class DisplayManagerFlags { Flags.FLAG_ENABLE_MODE_LIMIT_FOR_EXTERNAL_DISPLAY, Flags::enableModeLimitForExternalDisplay); + private final FlagState mBackUpSmoothDisplayAndForcePeakRefreshRateFlagState = new FlagState( + Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE, + Flags::backUpSmoothDisplayAndForcePeakRefreshRate); + /** Returns whether connected display management is enabled or not. */ public boolean isConnectedDisplayManagementEnabled() { return mConnectedDisplayManagementFlagState.isEnabled(); @@ -108,6 +112,10 @@ public class DisplayManagerFlags { return mDisplayOffloadFlagState.isEnabled(); } + public boolean isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled() { + return mBackUpSmoothDisplayAndForcePeakRefreshRateFlagState.isEnabled(); + } + private static class FlagState { private final String mName; @@ -138,19 +146,20 @@ public class DisplayManagerFlags { } private boolean flagOrSystemProperty(Supplier<Boolean> flagFunction, String flagName) { - // TODO(b/299462337) Remove when the infrastructure is ready. - if ((Build.IS_ENG || Build.IS_USERDEBUG) - && SystemProperties.getBoolean("persist.sys." + flagName, false)) { - return true; - } + boolean flagValue = false; try { - return flagFunction.get(); + flagValue = flagFunction.get(); } catch (Throwable ex) { if (DEBUG) { Slog.i(TAG, "Flags not ready yet. Return false for " + flagName, ex); } - return false; } + // TODO(b/299462337) Remove when the infrastructure is ready. + if (Build.IS_ENG || Build.IS_USERDEBUG) { + return SystemProperties.getBoolean("persist.sys." + flagName + "-override", + flagValue); + } + return flagValue; } } } 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 542f26cbec69..c24b3ca262be 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 @@ -72,3 +72,11 @@ flag { bug: "299521647" is_fixed_read_only: true } + +flag { + name: "back_up_smooth_display_and_force_peak_refresh_rate" + namespace: "display_manager" + description: "Feature flag for backing up Smooth Display and Force Peak Refresh Rate" + bug: "211737588" + is_fixed_read_only: true +} diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java index 71ea8cc30405..ca23844044ca 100644 --- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java @@ -22,6 +22,7 @@ import static android.os.PowerManager.BRIGHTNESS_INVALID_FLOAT; import static android.view.Display.Mode.INVALID_MODE_ID; import static com.android.server.display.DisplayDeviceConfig.DEFAULT_LOW_REFRESH_RATE; +import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay; import android.annotation.IntegerRes; import android.annotation.NonNull; @@ -176,6 +177,8 @@ public class DisplayModeDirector { private final boolean mIsDisplaysRefreshRatesSynchronizationEnabled; + private final boolean mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled; + public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler, @NonNull DisplayManagerFlags displayManagerFlags) { this(context, handler, new RealInjector(context), displayManagerFlags); @@ -191,6 +194,8 @@ public class DisplayModeDirector { .isExternalDisplayLimitModeEnabled(); mIsDisplaysRefreshRatesSynchronizationEnabled = displayManagerFlags .isDisplaysRefreshRatesSynchronizationEnabled(); + mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled = displayManagerFlags + .isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled(); mContext = context; mHandler = new DisplayModeDirectorHandler(handler.getLooper()); mInjector = injector; @@ -1193,8 +1198,7 @@ public class DisplayModeDirector { public void observe() { final ContentResolver cr = mContext.getContentResolver(); mInjector.registerPeakRefreshRateObserver(cr, this); - cr.registerContentObserver(mMinRefreshRateSetting, false /*notifyDescendants*/, this, - UserHandle.USER_SYSTEM); + mInjector.registerMinRefreshRateObserver(cr, this); cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM); cr.registerContentObserver(mMatchContentFrameRateSetting, false /*notifyDescendants*/, @@ -1292,10 +1296,34 @@ public class DisplayModeDirector { private void updateRefreshRateSettingLocked() { final ContentResolver cr = mContext.getContentResolver(); + float highestRefreshRate = findHighestRefreshRateForDefaultDisplay(mContext); + float minRefreshRate = Settings.System.getFloatForUser(cr, Settings.System.MIN_REFRESH_RATE, 0f, cr.getUserId()); + if (Float.isInfinite(minRefreshRate)) { + // Infinity means that we want the highest possible refresh rate + minRefreshRate = highestRefreshRate; + + if (!mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled) { + // The flag had been turned off, we need to restore the original value + Settings.System.putFloatForUser(cr, + Settings.System.MIN_REFRESH_RATE, minRefreshRate, cr.getUserId()); + } + } + float peakRefreshRate = Settings.System.getFloatForUser(cr, Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate, cr.getUserId()); + if (Float.isInfinite(peakRefreshRate)) { + // Infinity means that we want the highest possible refresh rate + peakRefreshRate = highestRefreshRate; + + if (!mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled) { + // The flag had been turned off, we need to restore the original value + Settings.System.putFloatForUser(cr, + Settings.System.PEAK_REFRESH_RATE, peakRefreshRate, cr.getUserId()); + } + } + updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate); } @@ -3082,6 +3110,7 @@ public class DisplayModeDirector { interface Injector { Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE); + Uri MIN_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.MIN_REFRESH_RATE); @NonNull DeviceConfigInterface getDeviceConfig(); @@ -3089,6 +3118,9 @@ public class DisplayModeDirector { void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, @NonNull ContentObserver observer); + void registerMinRefreshRateObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer); + void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener, Handler handler); @@ -3140,6 +3172,13 @@ public class DisplayModeDirector { } @Override + public void registerMinRefreshRateObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer) { + cr.registerContentObserver(MIN_REFRESH_RATE_URI, false /*notifyDescendants*/, + observer, UserHandle.USER_SYSTEM); + } + + @Override public void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) { getDisplayManager().registerDisplayListener(listener, handler); diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java index cd3d2f031455..0f40ca082663 100644 --- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java +++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java @@ -619,8 +619,8 @@ final class UpdatableFontDir { } return new FontConfig( - config.getFontFamilies(), config.getAliases(), mergedFamilies, mLastModifiedMillis, - mConfigVersion); + config.getFontFamilies(), config.getAliases(), mergedFamilies, + config.getLocaleFallbackCustomizations(), mLastModifiedMillis, mConfigVersion); } private PersistentSystemFontConfig.Config readPersistentConfig() { diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java index 2ede56dcecd9..a2c8748a9142 100644 --- a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java +++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java @@ -62,10 +62,10 @@ class GestureMonitorSpyWindow { mWindowHandle.ownerUid = uid; mWindowHandle.scaleFactor = 1.0f; mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */); - mWindowHandle.inputConfig = - InputConfig.NOT_FOCUSABLE | InputConfig.SPY | InputConfig.TRUSTED_OVERLAY; + mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.SPY; final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + mWindowHandle.setTrustedOverlay(t, mInputSurface, true); t.setInputWindowInfo(mInputSurface, mWindowHandle); t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_GESTURE_MONITOR); t.setPosition(mInputSurface, 0, 0); diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java index 0eb620f3f4df..bad6bf0f0141 100644 --- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java +++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java @@ -71,6 +71,7 @@ import android.widget.Toast; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.InputMethodSubtypeHandle; import com.android.internal.messages.nano.SystemMessageProto; import com.android.internal.notification.SystemNotificationChannels; @@ -99,7 +100,7 @@ import java.util.stream.Stream; * * @hide */ -final class KeyboardLayoutManager implements InputManager.InputDeviceListener { +class KeyboardLayoutManager implements InputManager.InputDeviceListener { private static final String TAG = "KeyboardLayoutManager"; @@ -1295,7 +1296,8 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener { } @SuppressLint("MissingPermission") - private List<ImeInfo> getImeInfoListForLayoutMapping() { + @VisibleForTesting + public List<ImeInfo> getImeInfoListForLayoutMapping() { List<ImeInfo> imeInfoList = new ArrayList<>(); UserManager userManager = Objects.requireNonNull( mContext.getSystemService(UserManager.class)); @@ -1402,7 +1404,8 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener { } } - private static class ImeInfo { + @VisibleForTesting + public static class ImeInfo { @UserIdInt int mUserId; @NonNull InputMethodSubtypeHandle mImeSubtypeHandle; @Nullable InputMethodSubtype mImeSubtype; diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java index 7726f40fa2ae..dbbbed31df76 100644 --- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java +++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java @@ -57,13 +57,13 @@ final class HandwritingEventReceiverSurface { InputConfig.NOT_FOCUSABLE | InputConfig.NOT_TOUCHABLE | InputConfig.SPY - | InputConfig.INTERCEPTS_STYLUS - | InputConfig.TRUSTED_OVERLAY; + | InputConfig.INTERCEPTS_STYLUS; // 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); diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index c9528d8257c4..9dec1dff4cf0 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -63,6 +63,7 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.function.pooled.PooledLambda; +import com.android.media.flags.Flags; import com.android.server.LocalServices; import com.android.server.pm.UserManagerInternal; @@ -161,11 +162,13 @@ class MediaRouter2ServiceImpl { mPowerManager = mContext.getSystemService(PowerManager.class); mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); - IntentFilter screenOnOffIntentFilter = new IntentFilter(); - screenOnOffIntentFilter.addAction(ACTION_SCREEN_ON); - screenOnOffIntentFilter.addAction(ACTION_SCREEN_OFF); + if (!Flags.disableScreenOffBroadcastReceiver()) { + IntentFilter screenOnOffIntentFilter = new IntentFilter(); + screenOnOffIntentFilter.addAction(ACTION_SCREEN_ON); + screenOnOffIntentFilter.addAction(ACTION_SCREEN_OFF); + mContext.registerReceiver(mScreenOnOffReceiver, screenOnOffIntentFilter); + } - mContext.registerReceiver(mScreenOnOffReceiver, screenOnOffIntentFilter); mContext.getPackageManager().addOnPermissionsChangeListener(this::onPermissionsChanged); MediaFeatureFlagManager.getInstance() @@ -2779,7 +2782,8 @@ class MediaRouter2ServiceImpl { List<ManagerRecord> managerRecords = getManagerRecords(); boolean isManagerScanning = false; - if (service.mPowerManager.isInteractive()) { + if (Flags.disableScreenOffBroadcastReceiver() + || service.mPowerManager.isInteractive()) { isManagerScanning = managerRecords.stream().anyMatch(manager -> manager.mIsScanning && service.mActivityManager .getPackageImportance(manager.mOwnerPackageName) diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java index f9876299e8e0..79cd2a0b236f 100644 --- a/services/core/java/com/android/server/pm/Computer.java +++ b/services/core/java/com/android/server/pm/Computer.java @@ -489,6 +489,9 @@ public interface Computer extends PackageDataSnapshot { boolean isPackageQuarantinedForUser(@NonNull String packageName, @UserIdInt int userId); + /** Check if the package is in a stopped state for a given user. */ + boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId); + boolean isSuspendingAnyPackages(@NonNull String suspendingPackage, @UserIdInt int userId); @NonNull diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index 5d2944e17943..7db7bf538c37 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -4938,7 +4938,7 @@ public class ComputerEngine implements Computer { int userId) { final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, - false /* checkShell */, "isPackageSuspendedForUser for user " + userId); + false /* checkShell */, "when asking about packages for user " + userId); final PackageStateInternal ps = mSettings.getPackage(packageName); if (ps == null || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) { throw new IllegalArgumentException("Unknown target package: " + packageName); @@ -4957,6 +4957,11 @@ public class ComputerEngine implements Computer { } @Override + public boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId) { + return getUserStageOrDefaultForUser(packageName, userId).isStopped(); + } + + @Override public boolean isSuspendingAnyPackages(@NonNull String suspendingPackage, @UserIdInt int userId) { for (final PackageStateInternal packageState : getPackageStates().values()) { diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java index 76203ac7650d..9a0306b77c41 100644 --- a/services/core/java/com/android/server/pm/IPackageManagerBase.java +++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java @@ -961,6 +961,12 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { } @Override + public final boolean isPackageStoppedForUser(@NonNull String packageName, + @UserIdInt int userId) { + return snapshot().isPackageStoppedForUser(packageName, userId); + } + + @Override @Deprecated public final boolean isSafeMode() { // allow instant applications diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java index 1c7024b7d239..2d192826ba9a 100644 --- a/services/core/java/com/android/server/pm/InstallRequest.java +++ b/services/core/java/com/android/server/pm/InstallRequest.java @@ -22,8 +22,6 @@ import static android.content.pm.PackageManager.INSTALL_SCENARIO_DEFAULT; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.os.Process.INVALID_UID; -import static com.android.server.art.model.DexoptResult.DexContainerFileDexoptResult; -import static com.android.server.art.model.DexoptResult.PackageDexoptResult; import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY; import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP; import static com.android.server.pm.PackageManagerService.TAG; @@ -58,7 +56,6 @@ import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import java.io.File; import java.util.ArrayList; -import java.util.LinkedHashSet; import java.util.List; final class InstallRequest { @@ -150,9 +147,6 @@ final class InstallRequest { @NonNull private int[] mUpdateBroadcastInstantUserIds = EMPTY_INT_ARRAY; - @NonNull - private ArrayList<String> mWarnings = new ArrayList<>(); - // New install InstallRequest(InstallingSession params) { mUserId = params.getUser().getIdentifier(); @@ -664,11 +658,6 @@ final class InstallRequest { return mUpdateBroadcastInstantUserIds; } - @NonNull - public ArrayList<String> getWarnings() { - return mWarnings; - } - public void setScanFlags(int scanFlags) { mScanFlags = scanFlags; } @@ -866,10 +855,6 @@ final class InstallRequest { } } - public void addWarning(@NonNull String warning) { - mWarnings.add(warning); - } - public void onPrepareStarted() { if (mPackageMetrics != null) { mPackageMetrics.onStepStarted(PackageMetrics.STEP_PREPARE); @@ -919,37 +904,22 @@ final class InstallRequest { } public void onDexoptFinished(DexoptResult dexoptResult) { - // Only report external profile warnings when installing from adb. The goal is to warn app - // developers if they have provided bad external profiles, so it's not beneficial to report - // those warnings in the normal app install workflow. - if (isInstallFromAdb()) { - var externalProfileErrors = new LinkedHashSet<String>(); - for (PackageDexoptResult packageResult : dexoptResult.getPackageDexoptResults()) { - for (DexContainerFileDexoptResult fileResult : - packageResult.getDexContainerFileDexoptResults()) { - externalProfileErrors.addAll(fileResult.getExternalProfileErrors()); - } - } - if (!externalProfileErrors.isEmpty()) { - addWarning("Error occurred during dexopt when processing external profiles:\n " - + String.join("\n ", externalProfileErrors)); - } + if (mPackageMetrics == null) { + return; } - - // Report dexopt metrics. - if (mPackageMetrics != null) { - mDexoptStatus = dexoptResult.getFinalStatus(); - if (mDexoptStatus == DexoptResult.DEXOPT_PERFORMED) { - long durationMillis = 0; - for (PackageDexoptResult packageResult : dexoptResult.getPackageDexoptResults()) { - for (DexContainerFileDexoptResult fileResult : - packageResult.getDexContainerFileDexoptResults()) { - durationMillis += fileResult.getDex2oatWallTimeMillis(); - } - } - mPackageMetrics.onStepFinished(PackageMetrics.STEP_DEXOPT, durationMillis); + mDexoptStatus = dexoptResult.getFinalStatus(); + if (mDexoptStatus != DexoptResult.DEXOPT_PERFORMED) { + return; + } + long durationMillis = 0; + for (DexoptResult.PackageDexoptResult packageResult : + dexoptResult.getPackageDexoptResults()) { + for (DexoptResult.DexContainerFileDexoptResult fileResult : + packageResult.getDexContainerFileDexoptResults()) { + durationMillis += fileResult.getDex2oatWallTimeMillis(); } } + mPackageMetrics.onStepFinished(PackageMetrics.STEP_DEXOPT, durationMillis); } public void onInstallCompleted() { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index d0e5f96f8d0f..662703992ad8 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -2930,40 +2930,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * @return a future that will be completed when the whole process is completed. */ private CompletableFuture<Void> install() { - // `futures` either contains only one session (`this`) or contains one parent session - // (`this`) and n-1 child sessions. List<CompletableFuture<InstallResult>> futures = installNonStaged(); CompletableFuture<InstallResult>[] arr = new CompletableFuture[futures.size()]; return CompletableFuture.allOf(futures.toArray(arr)).whenComplete((r, t) -> { if (t == null) { setSessionApplied(); - var multiPackageWarnings = new ArrayList<String>(); - if (isMultiPackage()) { - // This is a parent session. Collect warnings from children. - for (CompletableFuture<InstallResult> f : futures) { - InstallResult result = f.join(); - if (result.session != this && result.extras != null) { - ArrayList<String> childWarnings = result.extras.getStringArrayList( - PackageInstaller.EXTRA_WARNINGS); - if (!ArrayUtils.isEmpty(childWarnings)) { - multiPackageWarnings.addAll(childWarnings); - } - } - } - } for (CompletableFuture<InstallResult> f : futures) { InstallResult result = f.join(); - Bundle extras = result.extras; - if (isMultiPackage() && result.session == this - && !multiPackageWarnings.isEmpty()) { - if (extras == null) { - extras = new Bundle(); - } - extras.putStringArrayList( - PackageInstaller.EXTRA_WARNINGS, multiPackageWarnings); - } result.session.dispatchSessionFinished( - INSTALL_SUCCEEDED, "Session installed", extras); + INSTALL_SUCCEEDED, "Session installed", result.extras); } } else { PackageManagerException e = (PackageManagerException) t.getCause(); @@ -5214,10 +5189,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (!TextUtils.isEmpty(existing)) { fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing); } - ArrayList<String> warnings = extras.getStringArrayList(PackageInstaller.EXTRA_WARNINGS); - if (!ArrayUtils.isEmpty(warnings)) { - fillIn.putStringArrayListExtra(PackageInstaller.EXTRA_WARNINGS, warnings); - } } try { final BroadcastOptions options = BroadcastOptions.makeBasic(); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ddc8369738de..6260dd583bf9 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1434,9 +1434,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService break; } } - if (!request.getWarnings().isEmpty()) { - extras.putStringArrayList(PackageInstaller.EXTRA_WARNINGS, request.getWarnings()); - } return extras; } @@ -4501,6 +4498,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService boolean stopped, @UserIdInt int userId) { if (!mUserManager.exists(userId)) return; final int callingUid = Binder.getCallingUid(); + boolean wasStopped = false; if (snapshot.getInstantAppPackageName(callingUid) == null) { final int permission = mContext.checkCallingOrSelfPermission( Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); @@ -4522,6 +4520,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService ? null : packageState.getUserStateOrDefault(userId); if (packageState != null && packageUserState.isStopped() != stopped) { boolean wasNotLaunched = packageUserState.isNotLaunched(); + wasStopped = packageUserState.isStopped(); commitPackageStateMutation(null, packageName, state -> { PackageUserStateWrite userState = state.userState(userId); userState.setStopped(stopped); @@ -4553,6 +4552,24 @@ public class PackageManagerService implements PackageSender, TestUtilityService ah.setHibernatingGlobally(packageName, false); } }); + // Send UNSTOPPED broadcast if necessary + if (wasStopped && Flags.stayStopped()) { + final PackageManagerInternal pmi = + mInjector.getLocalService(PackageManagerInternal.class); + final int [] userIds = resolveUserIds(userId); + final SparseArray<int[]> broadcastAllowList = + snapshotComputer().getVisibilityAllowLists(packageName, userIds); + final Bundle extras = new Bundle(); + extras.putInt(Intent.EXTRA_UID, pmi.getPackageUid(packageName, 0, userId)); + extras.putInt(Intent.EXTRA_USER_HANDLE, userId); + mHandler.post(() -> { + mBroadcastHelper.sendPackageBroadcast(Intent.ACTION_PACKAGE_UNSTOPPED, + packageName, extras, + Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null, + userIds, null, broadcastAllowList, null, + null); + }); + } } } @@ -6929,6 +6946,25 @@ public class PackageManagerService implements PackageSender, TestUtilityService public ParceledListSlice<PackageInstaller.SessionInfo> getHistoricalSessions(int userId) { return mInstallerService.getHistoricalSessions(userId); } + + @Override + public void sendPackageRestartedBroadcast(@NonNull String packageName, + int uid, @Intent.Flags int flags) { + final int userId = UserHandle.getUserId(uid); + final int [] userIds = resolveUserIds(userId); + final SparseArray<int[]> broadcastAllowList = + snapshotComputer().getVisibilityAllowLists(packageName, userIds); + final Bundle extras = new Bundle(); + extras.putInt(Intent.EXTRA_UID, uid); + extras.putInt(Intent.EXTRA_USER_HANDLE, userId); + mHandler.post(() -> { + mBroadcastHelper.sendPackageBroadcast(Intent.ACTION_PACKAGE_RESTARTED, + packageName, extras, + flags, null, null, + userIds, null, broadcastAllowList, null, + null); + }); + } } private void setEnabledOverlayPackages(@UserIdInt int userId, diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 7264e2eff4aa..3a9272dc2003 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -4397,21 +4397,10 @@ class PackageManagerShellCommand extends ShellCommand { session.commit(receiver.getIntentSender()); if (!session.isStaged()) { final Intent result = receiver.getResult(); - int status = result.getIntExtra( - PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE); - List<String> warnings = - result.getStringArrayListExtra(PackageInstaller.EXTRA_WARNINGS); + final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, + PackageInstaller.STATUS_FAILURE); if (status == PackageInstaller.STATUS_SUCCESS) { - if (!ArrayUtils.isEmpty(warnings)) { - // Don't start the output string with "Success" because that will make adb - // treat this as a success. - for (String warning : warnings) { - pw.println("Warning: " + warning); - } - // Treat warnings as failure to draw app developers' attention. - status = PackageInstaller.STATUS_FAILURE; - pw.println("Completed with warning(s)"); - } else if (logSuccess) { + if (logSuccess) { pw.println("Success"); } } else { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 68a8e40d0528..0e98158d7210 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -75,13 +75,13 @@ import android.content.pm.parsing.FrameworkParsingPackageUtils; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; +import android.multiuser.Flags; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.Environment; import android.os.FileUtils; -import android.os.Flags; import android.os.Handler; import android.os.IBinder; import android.os.IProgressListener; @@ -1559,7 +1559,7 @@ public class UserManagerService extends IUserManager.Stub { logQuietModeEnabled(userId, enableQuietMode, callingPackage); // Broadcast generic intents for all profiles - if (Flags.allowPrivateProfile()) { + if (android.os.Flags.allowPrivateProfile()) { broadcastProfileAvailabilityChanges(profile, parent.getUserHandle(), enableQuietMode, false); } @@ -3785,6 +3785,8 @@ public class UserManagerService extends IUserManager.Stub { @GuardedBy({"mPackagesLock"}) private void readUserListLP() { + // Whether guest restrictions are present on userlist.xml + boolean guestRestrictionsArePresentOnUserListXml = false; try (ResilientAtomicFile file = getUserListFile()) { FileInputStream fin = null; try { @@ -3834,6 +3836,7 @@ public class UserManagerService extends IUserManager.Stub { } } } else if (name.equals(TAG_GUEST_RESTRICTIONS)) { + guestRestrictionsArePresentOnUserListXml = true; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && type != XmlPullParser.END_TAG) { if (type == XmlPullParser.START_TAG) { @@ -3852,6 +3855,7 @@ public class UserManagerService extends IUserManager.Stub { updateUserIds(); upgradeIfNecessaryLP(); + updateUsersWithFeatureFlags(guestRestrictionsArePresentOnUserListXml); } catch (Exception e) { // Remove corrupted file and retry. file.failRead(fin, e); @@ -3877,6 +3881,24 @@ public class UserManagerService extends IUserManager.Stub { } /** + * Update any user formats or Xml data that need to be updated based on the current user state + * and the feature flag settings. + */ + @GuardedBy({"mPackagesLock"}) + private void updateUsersWithFeatureFlags(boolean guestRestrictionsArePresentOnUserListXml) { + // User Xml re-writes are required when guest restrictions are saved on userlist.xml but + // as per the feature flag it should be on the SYSTEM user's xml or guest restrictions + // are saved on SYSTEM user's xml but as per the flags it should not be saved there. + if (guestRestrictionsArePresentOnUserListXml + == Flags.saveGlobalAndGuestRestrictionsOnSystemUserXmlReadOnly()) { + for (int userId: getUserIds()) { + writeUserLP(getUserDataNoChecks(userId)); + } + writeUserListLP(); + } + } + + /** * Version of {@link #upgradeIfNecessaryLP()} that takes in the userVersion for testing * purposes. For non-tests, use {@link #upgradeIfNecessaryLP()}. */ @@ -4393,9 +4415,24 @@ public class UserManagerService extends IUserManager.Stub { UserRestrictionsUtils.writeRestrictions(serializer, mBaseUserRestrictions.getRestrictions(userInfo.id), TAG_RESTRICTIONS); - UserRestrictionsUtils.writeRestrictions(serializer, - mDevicePolicyUserRestrictions.getRestrictions(UserHandle.USER_ALL), - TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS); + if (Flags.saveGlobalAndGuestRestrictionsOnSystemUserXmlReadOnly()) { + if (userInfo.id == UserHandle.USER_SYSTEM) { + UserRestrictionsUtils.writeRestrictions(serializer, + mDevicePolicyUserRestrictions.getRestrictions(UserHandle.USER_ALL), + TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS); + + serializer.startTag(null, TAG_GUEST_RESTRICTIONS); + synchronized (mGuestRestrictions) { + UserRestrictionsUtils.writeRestrictions(serializer, mGuestRestrictions, + TAG_RESTRICTIONS); + } + serializer.endTag(null, TAG_GUEST_RESTRICTIONS); + } + } else { + UserRestrictionsUtils.writeRestrictions(serializer, + mDevicePolicyUserRestrictions.getRestrictions(UserHandle.USER_ALL), + TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS); + } UserRestrictionsUtils.writeRestrictions(serializer, mDevicePolicyUserRestrictions.getRestrictions(userInfo.id), @@ -4471,12 +4508,15 @@ public class UserManagerService extends IUserManager.Stub { serializer.attributeInt(null, ATTR_USER_VERSION, mUserVersion); serializer.attributeInt(null, ATTR_USER_TYPE_VERSION, mUserTypeVersion); - serializer.startTag(null, TAG_GUEST_RESTRICTIONS); - synchronized (mGuestRestrictions) { - UserRestrictionsUtils - .writeRestrictions(serializer, mGuestRestrictions, TAG_RESTRICTIONS); + if (!Flags.saveGlobalAndGuestRestrictionsOnSystemUserXmlReadOnly()) { + serializer.startTag(null, TAG_GUEST_RESTRICTIONS); + synchronized (mGuestRestrictions) { + UserRestrictionsUtils + .writeRestrictions(serializer, mGuestRestrictions, + TAG_RESTRICTIONS); + } + serializer.endTag(null, TAG_GUEST_RESTRICTIONS); } - serializer.endTag(null, TAG_GUEST_RESTRICTIONS); int[] userIdsToWrite; synchronized (mUsersLock) { userIdsToWrite = new int[mUsers.size()]; @@ -4620,6 +4660,19 @@ public class UserManagerService extends IUserManager.Stub { localRestrictions = UserRestrictionsUtils.readRestrictions(parser); } else if (TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS.equals(tag)) { globalRestrictions = UserRestrictionsUtils.readRestrictions(parser); + } else if (TAG_GUEST_RESTRICTIONS.equals(tag)) { + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && type != XmlPullParser.END_TAG) { + if (type == XmlPullParser.START_TAG) { + if (parser.getName().equals(TAG_RESTRICTIONS)) { + synchronized (mGuestRestrictions) { + UserRestrictionsUtils + .readRestrictions(parser, mGuestRestrictions); + } + } + break; + } + } } else if (TAG_ACCOUNT.equals(tag)) { type = parser.next(); if (type == XmlPullParser.TEXT) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 097656cac7f7..3a6664a72439 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -333,6 +333,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP = 0; static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME = 1; + // must match: config_shortPressOnSettingsBehavior in config.xml + static final int SHORT_PRESS_SETTINGS_NOTHING = 0; + static final int SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL = 1; + static final int LAST_SHORT_PRESS_SETTINGS_BEHAVIOR = SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL; + static final int PENDING_KEY_NULL = -1; // Must match: config_shortPressOnStemPrimaryBehavior in config.xml @@ -611,6 +616,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // What we do when the user double-taps on home int mDoubleTapOnHomeBehavior; + // What we do when the user presses on settings + int mShortPressOnSettingsBehavior; + // Must match config_primaryShortPressTargetActivity in config.xml ComponentName mPrimaryShortPressTargetActivity; @@ -2766,6 +2774,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { mShortPressOnWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE; } + + mShortPressOnSettingsBehavior = res.getInteger( + com.android.internal.R.integer.config_shortPressOnSettingsBehavior); + if (mShortPressOnSettingsBehavior < SHORT_PRESS_SETTINGS_NOTHING + || mShortPressOnSettingsBehavior > LAST_SHORT_PRESS_SETTINGS_BEHAVIOR) { + mShortPressOnSettingsBehavior = SHORT_PRESS_SETTINGS_NOTHING; + } } private void updateSettings() { @@ -3632,6 +3647,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { Slog.wtf(TAG, "KEYCODE_STYLUS_BUTTON_* should be handled in" + " interceptKeyBeforeQueueing"); return true; + case KeyEvent.KEYCODE_SETTINGS: + if (mShortPressOnSettingsBehavior == SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL) { + if (!down) { + toggleNotificationPanel(); + logKeyboardSystemsEvent(event, KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL); + } + return true; + } + break; } if (isValidGlobalKey(keyCode) && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { @@ -6272,6 +6296,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print("mLongPressOnPowerBehavior="); pw.println(longPressOnPowerBehaviorToString(mLongPressOnPowerBehavior)); pw.print(prefix); + pw.print("mShortPressOnSettingsBehavior="); + pw.println(shortPressOnSettingsBehaviorToString(mShortPressOnSettingsBehavior)); + pw.print(prefix); pw.print("mLongPressOnPowerAssistantTimeoutMs="); pw.println(mLongPressOnPowerAssistantTimeoutMs); pw.print(prefix); @@ -6470,6 +6497,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private static String shortPressOnSettingsBehaviorToString(int behavior) { + switch (behavior) { + case SHORT_PRESS_SETTINGS_NOTHING: + return "SHORT_PRESS_SETTINGS_NOTHING"; + case SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL: + return "SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL"; + default: + return Integer.toString(behavior); + } + } + private static String veryLongPressOnPowerBehaviorToString(int behavior) { switch (behavior) { case VERY_LONG_PRESS_POWER_NOTHING: diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 9fd472057e43..12e1e2cd1e41 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -47,6 +47,7 @@ import static android.os.Process.SYSTEM_UID; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; +import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES; @@ -1592,6 +1593,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { } private void removePinnedRootTaskInSurfaceTransaction(Task rootTask) { + rootTask.mTransitionController.requestTransitionIfNeeded(TRANSIT_TO_BACK, 0 /* flags */, + rootTask, rootTask.mDisplayContent, null /* remoteTransition */, + null /* displayChange */); /** * Workaround: Force-stop all the activities in the root pinned task before we reparent them * to the fullscreen root task. This is to guarantee that when we are removing a root task, diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index 2439159164fd..73bcc8d94252 100644 --- a/services/core/java/com/android/server/wm/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -66,29 +66,29 @@ import java.util.Map; public final class CompatModePackages { /** - * {@link CompatModePackages#DOWNSCALED_INVERSE} is the gatekeeper of all per-app buffer inverse - * downscale changes. Enabling this change will allow the following scaling factors: - * {@link CompatModePackages#DOWNSCALE_90} - * {@link CompatModePackages#DOWNSCALE_85} - * {@link CompatModePackages#DOWNSCALE_80} - * {@link CompatModePackages#DOWNSCALE_75} - * {@link CompatModePackages#DOWNSCALE_70} - * {@link CompatModePackages#DOWNSCALE_65} - * {@link CompatModePackages#DOWNSCALE_60} - * {@link CompatModePackages#DOWNSCALE_55} - * {@link CompatModePackages#DOWNSCALE_50} - * {@link CompatModePackages#DOWNSCALE_45} - * {@link CompatModePackages#DOWNSCALE_40} - * {@link CompatModePackages#DOWNSCALE_35} - * {@link CompatModePackages#DOWNSCALE_30} + * <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> is the gatekeeper of all per-app buffer + * inverse downscale changes. Enabling this change will allow the following scaling factors: + * <a href="#DOWNSCALE_90">DOWNSCALE_90</a> + * <a href="#DOWNSCALE_85">DOWNSCALE_85</a> + * <a href="#DOWNSCALE_80">DOWNSCALE_80</a> + * <a href="#DOWNSCALE_75">DOWNSCALE_75</a> + * <a href="#DOWNSCALE_70">DOWNSCALE_70</a> + * <a href="#DOWNSCALE_65">DOWNSCALE_65</a> + * <a href="#DOWNSCALE_60">DOWNSCALE_60</a> + * <a href="#DOWNSCALE_55">DOWNSCALE_55</a> + * <a href="#DOWNSCALE_50">DOWNSCALE_50</a> + * <a href="#DOWNSCALE_45">DOWNSCALE_45</a> + * <a href="#DOWNSCALE_40">DOWNSCALE_40</a> + * <a href="#DOWNSCALE_35">DOWNSCALE_35</a> + * <a href="#DOWNSCALE_30">DOWNSCALE_30</a> * - * If {@link CompatModePackages#DOWNSCALED_INVERSE} is enabled for an app package, then the app - * will be forcibly resized to the lowest enabled scaling factor e.g. 1/0.8 if both 1/0.8 and - * 1/0.7 (* 100%) were enabled. + * If <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> is enabled for an app package, then + * the app will be forcibly resized to the lowest enabled scaling factor e.g. 1/0.8 if both + * 1/0.8 and 1/0.7 (* 100%) were enabled. * - * When both {@link CompatModePackages#DOWNSCALED_INVERSE} - * and {@link CompatModePackages#DOWNSCALED} are enabled, then - * {@link CompatModePackages#DOWNSCALED_INVERSE} takes precedence. + * When both <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> + * and <a href="#DOWNSCALED">DOWNSCALED</a> are enabled, then + * <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> takes precedence. */ @ChangeId @Disabled @@ -96,29 +96,29 @@ public final class CompatModePackages { public static final long DOWNSCALED_INVERSE = 273564678L; // This is a Bug ID. /** - * {@link CompatModePackages#DOWNSCALED} is the gatekeeper of all per-app buffer downscaling + * <a href="#DOWNSCALED">DOWNSCALED</a> is the gatekeeper of all per-app buffer downscaling * changes. Enabling this change will allow the following scaling factors: - * {@link CompatModePackages#DOWNSCALE_90} - * {@link CompatModePackages#DOWNSCALE_85} - * {@link CompatModePackages#DOWNSCALE_80} - * {@link CompatModePackages#DOWNSCALE_75} - * {@link CompatModePackages#DOWNSCALE_70} - * {@link CompatModePackages#DOWNSCALE_65} - * {@link CompatModePackages#DOWNSCALE_60} - * {@link CompatModePackages#DOWNSCALE_55} - * {@link CompatModePackages#DOWNSCALE_50} - * {@link CompatModePackages#DOWNSCALE_45} - * {@link CompatModePackages#DOWNSCALE_40} - * {@link CompatModePackages#DOWNSCALE_35} - * {@link CompatModePackages#DOWNSCALE_30} + * <a href="#DOWNSCALE_90">DOWNSCALE_90</a> + * <a href="#DOWNSCALE_85">DOWNSCALE_85</a> + * <a href="#DOWNSCALE_80">DOWNSCALE_80</a> + * <a href="#DOWNSCALE_75">DOWNSCALE_75</a> + * <a href="#DOWNSCALE_70">DOWNSCALE_70</a> + * <a href="#DOWNSCALE_65">DOWNSCALE_65</a> + * <a href="#DOWNSCALE_60">DOWNSCALE_60</a> + * <a href="#DOWNSCALE_55">DOWNSCALE_55</a> + * <a href="#DOWNSCALE_50">DOWNSCALE_50</a> + * <a href="#DOWNSCALE_45">DOWNSCALE_45</a> + * <a href="#DOWNSCALE_40">DOWNSCALE_40</a> + * <a href="#DOWNSCALE_35">DOWNSCALE_35</a> + * <a href="#DOWNSCALE_30">DOWNSCALE_30</a> * - * If {@link CompatModePackages#DOWNSCALED} is enabled for an app package, then the app will be + * If <a href="#DOWNSCALED">DOWNSCALED</a> is enabled for an app package, then the app will be * forcibly resized to the highest enabled scaling factor e.g. 80% if both 80% and 70% were * enabled. * - * When both {@link CompatModePackages#DOWNSCALED_INVERSE} - * and {@link CompatModePackages#DOWNSCALED} are enabled, then - * {@link CompatModePackages#DOWNSCALED_INVERSE} takes precedence. + * When both <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> + * and <a href="#DOWNSCALED">DOWNSCALED</a> are enabled, then + * <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> takes precedence. */ @ChangeId @Disabled @@ -126,12 +126,13 @@ public final class CompatModePackages { public static final long DOWNSCALED = 168419799L; /** - * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id - * {@link CompatModePackages#DOWNSCALE_90} for a package will force the app to assume it's + * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id + * <a href="#DOWNSCALE_90">DOWNSCALE_90</a> for a package will force the app to assume it's * running on a display with 90% the vertical and horizontal resolution of the real display. * - * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's - * running on a display with 111.11% the vertical and horizontal resolution of the real display + * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to + * assume it's running on a display with 111.11% the vertical and horizontal resolution of + * the real display */ @ChangeId @Disabled @@ -139,12 +140,13 @@ public final class CompatModePackages { public static final long DOWNSCALE_90 = 182811243L; /** - * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id - * {@link CompatModePackages#DOWNSCALE_85} for a package will force the app to assume it's + * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id + * <a href="#DOWNSCALE_85">DOWNSCALE_85</a> for a package will force the app to assume it's * running on a display with 85% the vertical and horizontal resolution of the real display. * - * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's - * running on a display with 117.65% the vertical and horizontal resolution of the real display + * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to + * assume it's running on a display with 117.65% the vertical and horizontal resolution of the + * real display */ @ChangeId @Disabled @@ -152,12 +154,13 @@ public final class CompatModePackages { public static final long DOWNSCALE_85 = 189969734L; /** - * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id - * {@link CompatModePackages#DOWNSCALE_80} for a package will force the app to assume it's + * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id + * <a href="#DOWNSCALE_80">DOWNSCALE_80</a> for a package will force the app to assume it's * running on a display with 80% the vertical and horizontal resolution of the real display. * - * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's - * running on a display with 125% the vertical and horizontal resolution of the real display + * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to + * assume it's running on a display with 125% the vertical and horizontal resolution of the real + * display */ @ChangeId @Disabled @@ -165,12 +168,13 @@ public final class CompatModePackages { public static final long DOWNSCALE_80 = 176926753L; /** - * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id - * {@link CompatModePackages#DOWNSCALE_75} for a package will force the app to assume it's + * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id + * <a href="#DOWNSCALE_75">DOWNSCALE_75</a> for a package will force the app to assume it's * running on a display with 75% the vertical and horizontal resolution of the real display. * - * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's - * running on a display with 133.33% the vertical and horizontal resolution of the real display + * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to + * assume it's running on a display with 133.33% the vertical and horizontal resolution of the + * real display */ @ChangeId @Disabled @@ -178,12 +182,13 @@ public final class CompatModePackages { public static final long DOWNSCALE_75 = 189969779L; /** - * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id - * {@link CompatModePackages#DOWNSCALE_70} for a package will force the app to assume it's + * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id + * <a href="#DOWNSCALE_70">DOWNSCALE_70</a> for a package will force the app to assume it's * running on a display with 70% the vertical and horizontal resolution of the real display. * - * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's - * running on a display with 142.86% the vertical and horizontal resolution of the real display + * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to + * assume it's running on a display with 142.86% the vertical and horizontal resolution of the + * real display */ @ChangeId @Disabled @@ -191,12 +196,13 @@ public final class CompatModePackages { public static final long DOWNSCALE_70 = 176926829L; /** - * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id - * {@link CompatModePackages#DOWNSCALE_65} for a package will force the app to assume it's + * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id + * <a href="#DOWNSCALE_65">DOWNSCALE_65</a> for a package will force the app to assume it's * running on a display with 65% the vertical and horizontal resolution of the real display. * - * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's - * running on a display with 153.85% the vertical and horizontal resolution of the real display + * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to + * assume it's running on a display with 153.85% the vertical and horizontal resolution of the + * real display */ @ChangeId @Disabled @@ -204,12 +210,13 @@ public final class CompatModePackages { public static final long DOWNSCALE_65 = 189969744L; /** - * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id - * {@link CompatModePackages#DOWNSCALE_60} for a package will force the app to assume it's + * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id + * <a href="#DOWNSCALE_60">DOWNSCALE_60</a> for a package will force the app to assume it's * running on a display with 60% the vertical and horizontal resolution of the real display. * - * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's - * running on a display with 166.67% the vertical and horizontal resolution of the real display + * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to + * assume it's running on a display with 166.67% the vertical and horizontal resolution of the + * real display */ @ChangeId @Disabled @@ -217,12 +224,13 @@ public final class CompatModePackages { public static final long DOWNSCALE_60 = 176926771L; /** - * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id - * {@link CompatModePackages#DOWNSCALE_55} for a package will force the app to assume it's + * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id + * <a href="#DOWNSCALE_55">DOWNSCALE_55</a> for a package will force the app to assume it's * running on a display with 55% the vertical and horizontal resolution of the real display. * - * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's - * running on a display with 181.82% the vertical and horizontal resolution of the real display + * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to + * assume it's running on a display with 181.82% the vertical and horizontal resolution of the + * real display */ @ChangeId @Disabled @@ -230,12 +238,13 @@ public final class CompatModePackages { public static final long DOWNSCALE_55 = 189970036L; /** - * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id - * {@link CompatModePackages#DOWNSCALE_50} for a package will force the app to assume it's + * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id + * <a href="#DOWNSCALE_50">DOWNSCALE_50</a> for a package will force the app to assume it's * running on a display with 50% vertical and horizontal resolution of the real display. * - * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's - * running on a display with 200% the vertical and horizontal resolution of the real display + * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to + * assume it's running on a display with 200% the vertical and horizontal resolution of the real + * display */ @ChangeId @Disabled @@ -243,12 +252,13 @@ public final class CompatModePackages { public static final long DOWNSCALE_50 = 176926741L; /** - * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id - * {@link CompatModePackages#DOWNSCALE_45} for a package will force the app to assume it's + * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id + * <a href="#DOWNSCALE_45">DOWNSCALE_45</a> for a package will force the app to assume it's * running on a display with 45% the vertical and horizontal resolution of the real display. * - * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's - * running on a display with 222.22% the vertical and horizontal resolution of the real display + * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to + * assume it's running on a display with 222.22% the vertical and horizontal resolution of the + * real display */ @ChangeId @Disabled @@ -256,12 +266,13 @@ public final class CompatModePackages { public static final long DOWNSCALE_45 = 189969782L; /** - * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id - * {@link CompatModePackages#DOWNSCALE_40} for a package will force the app to assume it's + * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id + * <a href="#DOWNSCALE_40">DOWNSCALE_40</a> for a package will force the app to assume it's * running on a display with 40% the vertical and horizontal resolution of the real display. * - * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's - * running on a display with 250% the vertical and horizontal resolution of the real display + * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to + * assume it's running on a display with 250% the vertical and horizontal resolution of the real + * display */ @ChangeId @Disabled @@ -269,12 +280,13 @@ public final class CompatModePackages { public static final long DOWNSCALE_40 = 189970038L; /** - * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id - * {@link CompatModePackages#DOWNSCALE_35} for a package will force the app to assume it's + * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id + * <a href="#DOWNSCALE_35">DOWNSCALE_35</a> for a package will force the app to assume it's * running on a display with 35% the vertical and horizontal resolution of the real display. * - * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's - * running on a display with 285.71% the vertical and horizontal resolution of the real display + * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to + * assume it's running on a display with 285.71% the vertical and horizontal resolution of the + * real display */ @ChangeId @Disabled @@ -282,12 +294,13 @@ public final class CompatModePackages { public static final long DOWNSCALE_35 = 189969749L; /** - * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id - * {@link CompatModePackages#DOWNSCALE_30} for a package will force the app to assume it's + * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id + * <a href="#DOWNSCALE_30">DOWNSCALE_30</a> for a package will force the app to assume it's * running on a display with 30% the vertical and horizontal resolution of the real display. * - * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's - * running on a display with 333.33% the vertical and horizontal resolution of the real display + * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to + * assume it's running on a display with 333.33% the vertical and horizontal resolution of the + * real display */ @ChangeId @Disabled diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index f6fe9b1dc63d..b7b5c2af0e3e 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -218,6 +218,7 @@ import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.DisplayShape; import android.view.Gravity; +import android.view.IDecorViewGestureListener; import android.view.IDisplayWindowInsetsController; import android.view.ISystemGestureExclusionListener; import android.view.IWindow; @@ -471,6 +472,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp private final RemoteCallbackList<ISystemGestureExclusionListener> mSystemGestureExclusionListeners = new RemoteCallbackList<>(); + private final RemoteCallbackList<IDecorViewGestureListener> mDecorViewGestureListener = + new RemoteCallbackList<>(); private final Region mSystemGestureExclusion = new Region(); private boolean mSystemGestureExclusionWasRestricted = false; private final Region mSystemGestureExclusionUnrestricted = new Region(); @@ -5968,6 +5971,27 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mSystemGestureExclusionListeners.unregister(listener); } + void registerDecorViewGestureListener(IDecorViewGestureListener listener) { + mDecorViewGestureListener.register(listener); + } + + void unregisterDecorViewGestureListener(IDecorViewGestureListener listener) { + mDecorViewGestureListener.unregister(listener); + } + + void updateDecorViewGestureIntercepted(IBinder token, boolean intercepted) { + for (int i = mDecorViewGestureListener.beginBroadcast() - 1; i >= 0; --i) { + try { + mDecorViewGestureListener + .getBroadcastItem(i) + .onInterceptionChanged(token, intercepted); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to notify DecorViewGestureListener", e); + } + } + mDecorViewGestureListener.finishBroadcast(); + } + void updateKeepClearAreas() { final Set<Rect> restrictedKeepClearAreas = new ArraySet<>(); final Set<Rect> unrestrictedKeepClearAreas = new ArraySet<>(); diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 0f1a1053716e..7af4aadb2f0e 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -48,7 +48,6 @@ import android.hardware.input.InputManagerGlobal; import android.os.Binder; import android.os.Build; import android.os.IBinder; -import android.os.InputConfig; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -186,6 +185,10 @@ class DragState { // Crop the input surface to the display size. mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); + // Make trusted overlay to not block any touches while D&D ongoing and allowing + // touches to pass through to windows underneath. This allows user to interact with the + // UI to navigate while dragging. + h.setTrustedOverlay(mTransaction, mInputSurface, true); mTransaction.show(mInputSurface) .setInputWindowInfo(mInputSurface, h) .setLayer(mInputSurface, Integer.MAX_VALUE) @@ -377,11 +380,6 @@ class DragState { mDragWindowHandle.ownerUid = MY_UID; mDragWindowHandle.scaleFactor = 1.0f; - // InputConfig.TRUSTED_OVERLAY: To not block any touches while D&D ongoing and allowing - // touches to pass through to windows underneath. This allows user to interact with the - // UI to navigate while dragging. - mDragWindowHandle.inputConfig = InputConfig.TRUSTED_OVERLAY; - // The drag window cannot receive new touches. mDragWindowHandle.touchableRegion.setEmpty(); diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java index 39622c1c5aaf..c21930dab5eb 100644 --- a/services/core/java/com/android/server/wm/InputConsumerImpl.java +++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java @@ -74,7 +74,7 @@ class InputConsumerImpl implements IBinder.DeathRecipient { mWindowHandle.ownerPid = WindowManagerService.MY_PID; mWindowHandle.ownerUid = WindowManagerService.MY_UID; mWindowHandle.scaleFactor = 1.0f; - mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.TRUSTED_OVERLAY; + mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE; mInputSurface = mService.makeSurfaceBuilder( mService.mRoot.getDisplayContent(displayId).getSession()) @@ -129,12 +129,14 @@ class InputConsumerImpl implements IBinder.DeathRecipient { void show(SurfaceControl.Transaction t, WindowContainer w) { t.show(mInputSurface); + mWindowHandle.setTrustedOverlay(t, mInputSurface, true); t.setInputWindowInfo(mInputSurface, mWindowHandle); t.setRelativeLayer(mInputSurface, w.getSurfaceControl(), 1); } void show(SurfaceControl.Transaction t, int layer) { t.show(mInputSurface); + mWindowHandle.setTrustedOverlay(t, mInputSurface, true); t.setInputWindowInfo(mInputSurface, mWindowHandle); t.setLayer(mInputSurface, layer); } diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 825d38b3eed7..af307ec3c2a9 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -675,6 +675,11 @@ final class InputMonitor { w.getKeyInterceptionInfo()); if (w.mWinAnimator.hasSurface()) { + // Update trusted overlay changes here because they are tied to input info. Input + // changes can be updated even if surfaces aren't. + inputWindowHandle.setTrustedOverlay(mInputTransaction, + w.mWinAnimator.mSurfaceController.mSurfaceControl, + w.isWindowTrustedOverlay()); populateInputWindowHandle(inputWindowHandle, w); setInputWindowInfoIfNeeded(mInputTransaction, w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle); @@ -732,7 +737,7 @@ final class InputMonitor { new InputWindowHandle(null /* inputApplicationHandle */, displayId)); inputWindowHandle.setName(name); inputWindowHandle.setLayoutParamsType(TYPE_SECURE_SYSTEM_OVERLAY); - inputWindowHandle.setTrustedOverlay(true); + inputWindowHandle.setTrustedOverlay(t, sc, true); populateOverlayInputInfo(inputWindowHandle); setInputWindowInfoIfNeeded(t, sc, inputWindowHandle); } diff --git a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java index 64b7a6064e45..90d81bd82087 100644 --- a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java +++ b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java @@ -195,6 +195,11 @@ class InputWindowHandleWrapper { mChanged = true; } + void setTrustedOverlay(SurfaceControl.Transaction t, SurfaceControl sc, + boolean trustedOverlay) { + mHandle.setTrustedOverlay(t, sc, trustedOverlay); + } + void setOwnerPid(int pid) { if (mHandle.ownerPid == pid) { return; diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index c3977d6918e3..82d4b90d06be 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -62,6 +62,7 @@ import android.window.PictureInPictureSurfaceTransaction; import android.window.TaskSnapshot; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.IResultReceiver; import com.android.internal.protolog.common.ProtoLog; import com.android.server.LocalServices; import com.android.server.inputmethod.InputMethodManagerInternal; @@ -244,7 +245,8 @@ public class RecentsAnimationController implements DeathRecipient { } @Override - public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint) { + public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint, + IResultReceiver finishCb) { ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "finish(%b): mCanceled=%b", moveHomeToTop, mCanceled); final long token = Binder.clearCallingIdentity(); @@ -257,6 +259,13 @@ public class RecentsAnimationController implements DeathRecipient { } finally { Binder.restoreCallingIdentity(token); } + if (finishCb != null) { + try { + finishCb.send(0, new Bundle()); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to report animation finished", e); + } + } } @Override diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index e6d48667ffb0..3775ccd79d4c 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -560,6 +560,16 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } @Override + public void reportDecorViewGestureInterceptionChanged(IWindow window, boolean intercepted) { + final long ident = Binder.clearCallingIdentity(); + try { + mService.reportDecorViewGestureChanged(this, window, intercepted); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override public void reportKeepClearAreasChanged(IWindow window, List<Rect> restricted, List<Rect> unrestricted) { if (!mSetsUnrestrictedKeepClearAreas && !unrestricted.isEmpty()) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 44d4c4516842..c9107e8cf5f3 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -249,6 +249,7 @@ import android.view.DisplayInfo; import android.view.Gravity; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.ICrossWindowBlurEnabledListener; +import android.view.IDecorViewGestureListener; import android.view.IDisplayChangeWindowController; import android.view.IDisplayFoldListener; import android.view.IDisplayWindowInsetsController; @@ -4629,8 +4630,9 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent == null) { - throw new IllegalArgumentException("Trying to register visibility event " - + "for invalid display: " + displayId); + throw new IllegalArgumentException( + "Trying to register system gesture exclusion event for invalid display: " + + displayId); } displayContent.registerSystemGestureExclusionListener(listener); } @@ -4642,13 +4644,64 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent == null) { - throw new IllegalArgumentException("Trying to register visibility event " - + "for invalid display: " + displayId); + throw new IllegalArgumentException( + "Trying to unregister system gesture exclusion event for invalid display: " + + displayId); } displayContent.unregisterSystemGestureExclusionListener(listener); } } + @Override + public void registerDecorViewGestureListener( + IDecorViewGestureListener listener, int displayId) { + if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT, + "registerDecorViewGestureListener()")) { + throw new SecurityException("Requires MONITOR_INPUT permission"); + } + synchronized (mGlobalLock) { + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); + if (displayContent == null) { + throw new IllegalArgumentException( + "Trying to register DecorView gesture event listener" + + "for invalid display: " + + displayId); + } + displayContent.registerDecorViewGestureListener(listener); + } + } + + @Override + public void unregisterDecorViewGestureListener( + IDecorViewGestureListener listener, int displayId) { + if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT, + "unregisterSystemGestureExclusionListener()")) { + throw new SecurityException("Requires MONITOR_INPUT permission"); + } + synchronized (mGlobalLock) { + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); + if (displayContent == null) { + throw new IllegalArgumentException( + "Trying to unregister DecorView gesture event listener" + + "for invalid display: " + + displayId); + } + displayContent.unregisterDecorViewGestureListener(listener); + } + } + + void reportDecorViewGestureChanged(Session session, IWindow window, boolean intercepted) { + synchronized (mGlobalLock) { + final WindowState win = + windowForClientLocked(session, window, false /* throwOnError */); + if (win == null) { + return; + } + win.getDisplayContent() + .updateDecorViewGestureIntercepted(win.mToken.token, intercepted); + } + } + void reportSystemGestureExclusionChanged(Session session, IWindow window, List<Rect> exclusionRects) { synchronized (mGlobalLock) { @@ -8876,11 +8929,6 @@ public class WindowManagerService extends IWindowManager.Stub h.inputConfig |= InputConfig.NOT_FOCUSABLE; } - // Check private trusted overlay flag to set trustedOverlay field of input window handle. - if ((privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) { - h.inputConfig |= InputConfig.TRUSTED_OVERLAY; - } - h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS; h.ownerUid = callingUid; h.ownerPid = callingPid; @@ -8900,6 +8948,8 @@ public class WindowManagerService extends IWindowManager.Stub } final SurfaceControl.Transaction t = mTransactionFactory.get(); + // Check private trusted overlay flag to set trustedOverlay field of input window handle. + h.setTrustedOverlay(t, surface, (privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0); t.setInputWindowInfo(surface, h); t.apply(); t.close(); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index ebef606a8d60..4beec2bc79e6 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -178,6 +178,7 @@ 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.surfaceTrustedOverlay; import android.annotation.CallSuper; import android.annotation.NonNull; @@ -1110,7 +1111,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mInputWindowHandle.setName(getName()); mInputWindowHandle.setPackageName(mAttrs.packageName); mInputWindowHandle.setLayoutParamsType(mAttrs.type); - mInputWindowHandle.setTrustedOverlay(shouldWindowHandleBeTrusted(s)); + if (!surfaceTrustedOverlay()) { + mInputWindowHandle.setTrustedOverlay(isWindowTrustedOverlay()); + } if (DEBUG) { Slog.v(TAG, "Window " + this + " client=" + c.asBinder() + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a); @@ -1185,12 +1188,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - boolean shouldWindowHandleBeTrusted(Session s) { + public boolean isWindowTrustedOverlay() { return InputMonitor.isTrustedOverlay(mAttrs.type) || ((mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0 - && s.mCanAddInternalSystemWindow) + && mSession.mCanAddInternalSystemWindow) || ((mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY) != 0 - && s.mCanCreateSystemApplicationOverlay); + && mSession.mCanCreateSystemApplicationOverlay); } int getTouchOcclusionMode() { @@ -5187,6 +5190,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP updateFrameRateSelectionPriorityIfNeeded(); updateScaleIfNeeded(); mWinAnimator.prepareSurfaceLocked(getSyncTransaction()); + if (surfaceTrustedOverlay()) { + getSyncTransaction().setTrustedOverlay(mSurfaceControl, isWindowTrustedOverlay()); + } } super.prepareSurfaces(); } @@ -5939,7 +5945,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } boolean isTrustedOverlay() { - return mInputWindowHandle.isTrustedOverlay(); + if (surfaceTrustedOverlay()) { + WindowState parentWindow = getParentWindow(); + return isWindowTrustedOverlay() || (parentWindow != null + && parentWindow.isWindowTrustedOverlay()); + } else { + return mInputWindowHandle.isTrustedOverlay(); + } } public boolean receiveFocusFromTapOutside() { diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index d0a9c458a20f..debd891400b6 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -46,6 +46,8 @@ <xs:annotation name="nonnull"/> <xs:annotation name="final"/> </xs:element> + <xs:element type="powerThrottlingConfig" name="powerThrottlingConfig" minOccurs="0" + maxOccurs="1"/> <xs:element type="luxThrottling" name="luxThrottling" minOccurs="0" maxOccurs="1"/> <xs:element type="highBrightnessMode" name="highBrightnessMode" minOccurs="0" @@ -350,6 +352,43 @@ </xs:sequence> </xs:complexType> + <xs:complexType name="powerThrottlingMap"> + <xs:sequence> + <xs:element name="powerThrottlingPoint" type="powerThrottlingPoint" maxOccurs="unbounded" minOccurs="1"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + </xs:sequence> + <xs:attribute name="id" type="xs:string"/> + </xs:complexType> + + <xs:complexType name="powerThrottlingPoint"> + <xs:sequence> + <xs:element type="thermalStatus" name="thermalStatus"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + <xs:element type="nonNegativeDecimal" name="powerQuotaMilliWatts"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="powerThrottlingConfig"> + <xs:element type="nonNegativeDecimal" name="brightnessLowestCapAllowed"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + <xs:element name="pollingWindowMillis" type="xs:nonNegativeInteger"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + <xs:element type="powerThrottlingMap" name="powerThrottlingMap" maxOccurs="unbounded"> + <xs:annotation name="final"/> + </xs:element> + </xs:complexType> + <xs:complexType name="nitsMap"> <xs:sequence> <xs:element name="point" type="point" maxOccurs="unbounded" minOccurs="2"> diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index 949b1f2cb74b..2d27f0c79660 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -106,6 +106,7 @@ package com.android.server.display.config { method public final com.android.server.display.config.SensorDetails getLightSensor(); method public com.android.server.display.config.LuxThrottling getLuxThrottling(); method @Nullable public final String getName(); + method public com.android.server.display.config.PowerThrottlingConfig getPowerThrottlingConfig(); method public final com.android.server.display.config.SensorDetails getProxSensor(); method public com.android.server.display.config.DisplayQuirks getQuirks(); method public com.android.server.display.config.RefreshRateConfigs getRefreshRate(); @@ -138,6 +139,7 @@ package com.android.server.display.config { method public final void setLightSensor(com.android.server.display.config.SensorDetails); method public void setLuxThrottling(com.android.server.display.config.LuxThrottling); method public final void setName(@Nullable String); + method public void setPowerThrottlingConfig(com.android.server.display.config.PowerThrottlingConfig); method public final void setProxSensor(com.android.server.display.config.SensorDetails); method public void setQuirks(com.android.server.display.config.DisplayQuirks); method public void setRefreshRate(com.android.server.display.config.RefreshRateConfigs); @@ -246,6 +248,30 @@ package com.android.server.display.config { method public final void setValue(@NonNull java.math.BigDecimal); } + public class PowerThrottlingConfig { + ctor public PowerThrottlingConfig(); + method @NonNull public final java.math.BigDecimal getBrightnessLowestCapAllowed(); + method @NonNull public final java.math.BigInteger getPollingWindowMillis(); + method public final java.util.List<com.android.server.display.config.PowerThrottlingMap> getPowerThrottlingMap(); + method public final void setBrightnessLowestCapAllowed(@NonNull java.math.BigDecimal); + method public final void setPollingWindowMillis(@NonNull java.math.BigInteger); + } + + public class PowerThrottlingMap { + ctor public PowerThrottlingMap(); + method public String getId(); + method @NonNull public final java.util.List<com.android.server.display.config.PowerThrottlingPoint> getPowerThrottlingPoint(); + method public void setId(String); + } + + public class PowerThrottlingPoint { + ctor public PowerThrottlingPoint(); + method @NonNull public final java.math.BigDecimal getPowerQuotaMilliWatts(); + method @NonNull public final com.android.server.display.config.ThermalStatus getThermalStatus(); + method public final void setPowerQuotaMilliWatts(@NonNull java.math.BigDecimal); + method public final void setThermalStatus(@NonNull com.android.server.display.config.ThermalStatus); + } + public enum PredefinedBrightnessLimitNames { method public String getRawName(); enum_constant public static final com.android.server.display.config.PredefinedBrightnessLimitNames _default; diff --git a/services/core/xsd/display-layout-config/display-layout-config.xsd b/services/core/xsd/display-layout-config/display-layout-config.xsd index 57b5d00f75a0..4e954653bcbb 100644 --- a/services/core/xsd/display-layout-config/display-layout-config.xsd +++ b/services/core/xsd/display-layout-config/display-layout-config.xsd @@ -52,6 +52,7 @@ <xs:element name="address" type="xs:nonNegativeInteger"/> <xs:element name="position" type="xs:string" minOccurs="0" maxOccurs="1" /> <xs:element name="brightnessThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" /> + <xs:element name="powerThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" /> <xs:element name="refreshRateThermalThrottlingMapId" type="xs:string" minOccurs="0" /> <xs:element name="leadDisplayAddress" type="xs:nonNegativeInteger" minOccurs="0" maxOccurs="1" /> </xs:sequence> diff --git a/services/core/xsd/display-layout-config/schema/current.txt b/services/core/xsd/display-layout-config/schema/current.txt index 2d4f7a428db1..195cae5aee14 100644 --- a/services/core/xsd/display-layout-config/schema/current.txt +++ b/services/core/xsd/display-layout-config/schema/current.txt @@ -8,6 +8,7 @@ package com.android.server.display.config.layout { method public String getDisplayGroup(); method public java.math.BigInteger getLeadDisplayAddress(); method public String getPosition(); + method public String getPowerThrottlingMapId(); method public String getRefreshRateThermalThrottlingMapId(); method public String getRefreshRateZoneId(); method public boolean isDefaultDisplay(); @@ -19,6 +20,7 @@ package com.android.server.display.config.layout { method public void setEnabled(boolean); method public void setLeadDisplayAddress(java.math.BigInteger); method public void setPosition(String); + method public void setPowerThrottlingMapId(String); method public void setRefreshRateThermalThrottlingMapId(String); method public void setRefreshRateZoneId(String); } diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index a4adf5866f3d..08df65169224 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -65,6 +65,7 @@ import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.content.PackageMonitor; import com.android.server.credentials.metrics.ApiName; import com.android.server.credentials.metrics.ApiStatus; import com.android.server.infra.AbstractMasterSystemService; @@ -89,7 +90,7 @@ import java.util.stream.Collectors; */ public final class CredentialManagerService extends AbstractMasterSystemService< - CredentialManagerService, CredentialManagerServiceImpl> { + CredentialManagerService, CredentialManagerServiceImpl> { private static final String TAG = "CredManSysService"; private static final String PERMISSION_DENIED_ERROR = "permission_denied"; @@ -110,8 +111,7 @@ public final class CredentialManagerService /** Cache of all ongoing request sessions per user id. */ @GuardedBy("mLock") - private final SparseArray<Map<IBinder, RequestSession>> mRequestSessions = - new SparseArray<>(); + private final SparseArray<Map<IBinder, RequestSession>> mRequestSessions = new SparseArray<>(); private final SessionManager mSessionManager = new SessionManager(); @@ -123,6 +123,8 @@ public final class CredentialManagerService null, PACKAGE_UPDATE_POLICY_REFRESH_EAGER); mContext = context; + + mPackageMonitor.register(context, context.getMainLooper(), false); } @NonNull @@ -139,8 +141,7 @@ public final class CredentialManagerService serviceInfos.forEach( info -> { services.add( - new CredentialManagerServiceImpl(this, mLock, resolvedUserId, - info)); + new CredentialManagerServiceImpl(this, mLock, resolvedUserId, info)); }); return services; } @@ -216,8 +217,8 @@ public final class CredentialManagerService for (CredentialManagerServiceImpl serviceToBeRemoved : servicesToBeRemoved) { removeServiceFromCache(serviceToBeRemoved, userId); removeServiceFromSystemServicesCache(serviceToBeRemoved, userId); - removeServiceFromMultiModeSettings(serviceToBeRemoved.getComponentName() - .flattenToString(), userId); + removeServiceFromMultiModeSettings( + serviceToBeRemoved.getComponentName().flattenToString(), userId); CredentialDescriptionRegistry.forUser(userId) .evictProviderWithPackageName(serviceToBeRemoved.getServicePackageName()); } @@ -286,13 +287,20 @@ public final class CredentialManagerService } private static Set<ComponentName> getPrimaryProvidersForUserId(Context context, int userId) { - final int resolvedUserId = ActivityManager.handleIncomingUser( - Binder.getCallingPid(), Binder.getCallingUid(), - userId, false, false, - "getPrimaryProvidersForUserId", null); - SecureSettingsServiceNameResolver resolver = new SecureSettingsServiceNameResolver( - context, Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, - /* isMultipleMode= */ true); + final int resolvedUserId = + ActivityManager.handleIncomingUser( + Binder.getCallingPid(), + Binder.getCallingUid(), + userId, + false, + false, + "getPrimaryProvidersForUserId", + null); + SecureSettingsServiceNameResolver resolver = + new SecureSettingsServiceNameResolver( + context, + Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, + /* isMultipleMode= */ true); String[] serviceNames = resolver.readServiceNameList(resolvedUserId); if (serviceNames == null) { return new HashSet<ComponentName>(); @@ -329,7 +337,8 @@ public final class CredentialManagerService final long origId = Binder.clearCallingIdentity(); try { return DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API, + DeviceConfig.NAMESPACE_CREDENTIAL, + DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API, false); } finally { Binder.restoreCallingIdentity(origId); @@ -345,13 +354,14 @@ public final class CredentialManagerService List<ProviderSession> providerSessions = new ArrayList<>(); for (Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult> result : activeCredentialContainers) { - ProviderSession providerSession = ProviderRegistryGetSession.createNewSession( - mContext, - UserHandle.getCallingUserId(), - session, - session.mClientAppInfo, - result.second.mPackageName, - result.first); + ProviderSession providerSession = + ProviderRegistryGetSession.createNewSession( + mContext, + UserHandle.getCallingUserId(), + session, + session.mClientAppInfo, + result.second.mPackageName, + result.first); providerSessions.add(providerSession); session.addProviderSession(providerSession.getComponentName(), providerSession); } @@ -367,23 +377,23 @@ public final class CredentialManagerService List<ProviderSession> providerSessions = new ArrayList<>(); for (Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult> result : activeCredentialContainers) { - ProviderSession providerSession = ProviderRegistryGetSession.createNewSession( - mContext, - UserHandle.getCallingUserId(), - session, - session.mClientAppInfo, - result.second.mPackageName, - result.first); + ProviderSession providerSession = + ProviderRegistryGetSession.createNewSession( + mContext, + UserHandle.getCallingUserId(), + session, + session.mClientAppInfo, + result.second.mPackageName, + result.first); providerSessions.add(providerSession); session.addProviderSession(providerSession.getComponentName(), providerSession); } return providerSessions; } - @NonNull private Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>> - getFilteredResultFromRegistry(List<CredentialOption> options) { + getFilteredResultFromRegistry(List<CredentialOption> options) { // Session for active/provisioned credential descriptions; CredentialDescriptionRegistry registry = CredentialDescriptionRegistry.forUser(UserHandle.getCallingUserId()); @@ -393,10 +403,12 @@ public final class CredentialManagerService options.stream() .map( getCredentialOption -> - new HashSet<>(getCredentialOption - .getCredentialRetrievalData() - .getStringArrayList( - CredentialOption.SUPPORTED_ELEMENT_KEYS))) + new HashSet<>( + getCredentialOption + .getCredentialRetrievalData() + .getStringArrayList( + CredentialOption + .SUPPORTED_ELEMENT_KEYS))) .collect(Collectors.toSet()); // All requested credential descriptions based on the given request. @@ -408,12 +420,14 @@ public final class CredentialManagerService for (CredentialDescriptionRegistry.FilterResult filterResult : filterResults) { for (CredentialOption credentialOption : options) { - Set<String> requestedElementKeys = new HashSet<>( - credentialOption - .getCredentialRetrievalData() - .getStringArrayList(CredentialOption.SUPPORTED_ELEMENT_KEYS)); - if (CredentialDescriptionRegistry.checkForMatch(filterResult.mElementKeys, - requestedElementKeys)) { + Set<String> requestedElementKeys = + new HashSet<>( + credentialOption + .getCredentialRetrievalData() + .getStringArrayList( + CredentialOption.SUPPORTED_ELEMENT_KEYS)); + if (CredentialDescriptionRegistry.checkForMatch( + filterResult.mElementKeys, requestedElementKeys)) { result.add(new Pair<>(credentialOption, filterResult)); } } @@ -449,9 +463,7 @@ public final class CredentialManagerService } private CallingAppInfo constructCallingAppInfo( - String realPackageName, - int userId, - @Nullable String origin) { + String realPackageName, int userId, @Nullable String origin) { final PackageInfo packageInfo; CallingAppInfo callingAppInfo; try { @@ -477,8 +489,7 @@ public final class CredentialManagerService GetCredentialRequest request, IGetCandidateCredentialsCallback callback, final String callingPackage) { - Slog.i(TAG, "starting getCandidateCredentials with callingPackage: " - + callingPackage); + Slog.i(TAG, "starting getCandidateCredentials with callingPackage: " + callingPackage); ICancellationSignal cancelTransport = CancellationSignal.createTransport(); final int userId = UserHandle.getCallingUserId(); @@ -496,8 +507,7 @@ public final class CredentialManagerService request, constructCallingAppInfo(callingPackage, userId, request.getOrigin()), getEnabledProvidersForUser(userId), - CancellationSignal.fromTransport(cancelTransport) - ); + CancellationSignal.fromTransport(cancelTransport)); addSessionLocked(userId, session); List<ProviderSession> providerSessions = @@ -531,8 +541,7 @@ public final class CredentialManagerService IGetCredentialCallback callback, final String callingPackage) { final long timestampBegan = System.nanoTime(); - Slog.i(TAG, "starting executeGetCredential with callingPackage: " - + callingPackage); + Slog.i(TAG, "starting executeGetCredential with callingPackage: " + callingPackage); ICancellationSignal cancelTransport = CancellationSignal.createTransport(); final int userId = UserHandle.getCallingUserId(); @@ -557,8 +566,7 @@ public final class CredentialManagerService timestampBegan); addSessionLocked(userId, session); - List<ProviderSession> providerSessions = - prepareProviderSessions(request, session); + List<ProviderSession> providerSessions = prepareProviderSessions(request, session); if (providerSessions.isEmpty()) { try { @@ -617,15 +625,17 @@ public final class CredentialManagerService if (providerSessions.isEmpty()) { try { prepareGetCredentialCallback.onResponse( - new PrepareGetCredentialResponseInternal(PermissionUtils.hasPermission( - mContext, - callingPackage, - Manifest.permission - .CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS), - /*credentialResultTypes=*/null, - /*hasAuthenticationResults=*/false, - /*hasRemoteResults=*/false, - /*pendingIntent=*/null)); + new PrepareGetCredentialResponseInternal( + PermissionUtils.hasPermission( + mContext, + callingPackage, + Manifest.permission + .CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS + ), + /* credentialResultTypes= */ null, + /* hasAuthenticationResults= */ false, + /* hasRemoteResults= */ false, + /* pendingIntent= */ null)); } catch (RemoteException e) { Slog.e( TAG, @@ -641,27 +651,32 @@ public final class CredentialManagerService } private List<ProviderSession> prepareProviderSessions( - GetCredentialRequest request, - GetRequestSession session) { + GetCredentialRequest request, GetRequestSession session) { List<ProviderSession> providerSessions; if (isCredentialDescriptionApiEnabled()) { List<CredentialOption> optionsThatRequireActiveCredentials = request.getCredentialOptions().stream() - .filter(credentialOption -> credentialOption - .getCredentialRetrievalData() - .getStringArrayList( - CredentialOption - .SUPPORTED_ELEMENT_KEYS) != null) + .filter( + credentialOption -> + credentialOption + .getCredentialRetrievalData() + .getStringArrayList( + CredentialOption + .SUPPORTED_ELEMENT_KEYS) + != null) .toList(); List<CredentialOption> optionsThatDoNotRequireActiveCredentials = request.getCredentialOptions().stream() - .filter(credentialOption -> credentialOption - .getCredentialRetrievalData() - .getStringArrayList( - CredentialOption - .SUPPORTED_ELEMENT_KEYS) == null) + .filter( + credentialOption -> + credentialOption + .getCredentialRetrievalData() + .getStringArrayList( + CredentialOption + .SUPPORTED_ELEMENT_KEYS) + == null) .toList(); List<ProviderSession> sessionsWithoutRemoteService = @@ -706,8 +721,7 @@ public final class CredentialManagerService ICreateCredentialCallback callback, String callingPackage) { final long timestampBegan = System.nanoTime(); - Slog.i(TAG, "starting executeCreateCredential with callingPackage: " - + callingPackage); + Slog.i(TAG, "starting executeCreateCredential with callingPackage: " + callingPackage); ICancellationSignal cancelTransport = CancellationSignal.createTransport(); if (request.getOrigin() != null) { @@ -756,8 +770,8 @@ public final class CredentialManagerService } catch (RemoteException e) { Slog.e( TAG, - "Issue invoking onError on ICreateCredentialCallback " - + "callback: ", e); + "Issue invoking onError on ICreateCredentialCallback " + "callback: ", + e); } } @@ -770,8 +784,8 @@ public final class CredentialManagerService try { var initMetric = session.mRequestSessionMetric.getInitialPhaseMetric(); initMetric.setCredentialServiceBeginQueryTimeNanoseconds(System.nanoTime()); - MetricUtilities.logApiCalledInitialPhase(initMetric, - session.mRequestSessionMetric.returnIncrementSequence()); + MetricUtilities.logApiCalledInitialPhase( + initMetric, session.mRequestSessionMetric.returnIncrementSequence()); } catch (Exception e) { Slog.i(TAG, "Unexpected error during metric logging: ", e); } @@ -779,25 +793,32 @@ public final class CredentialManagerService @Override public void setEnabledProviders( - List<String> primaryProviders, List<String> providers, int userId, + List<String> primaryProviders, + List<String> providers, + int userId, ISetEnabledProvidersCallback callback) { final int callingUid = Binder.getCallingUid(); if (!hasWriteSecureSettingsPermission()) { try { MetricUtilities.logApiCalledSimpleV2( - ApiName.SET_ENABLED_PROVIDERS, - ApiStatus.FAILURE, callingUid); + ApiName.SET_ENABLED_PROVIDERS, ApiStatus.FAILURE, callingUid); callback.onError( PERMISSION_DENIED_ERROR, PERMISSION_DENIED_WRITE_SECURE_SETTINGS_ERROR); } catch (RemoteException e) { MetricUtilities.logApiCalledSimpleV2( - ApiName.SET_ENABLED_PROVIDERS, - ApiStatus.FAILURE, callingUid); + ApiName.SET_ENABLED_PROVIDERS, ApiStatus.FAILURE, callingUid); Slog.e(TAG, "Issue with invoking response: ", e); } return; } + // If we don't have any primary providers enabled anymore then + // we should erase all the providers since the feature is + // now disabled. + if (primaryProviders.isEmpty()) { + providers.clear(); + } + userId = ActivityManager.handleIncomingUser( Binder.getCallingPid(), @@ -808,17 +829,19 @@ public final class CredentialManagerService "setEnabledProviders", null); - Set<String> enableProvider = new HashSet<>(providers); - enableProvider.addAll(primaryProviders); + Set<String> enabledProviders = new HashSet<>(providers); + enabledProviders.addAll(primaryProviders); boolean writeEnabledStatus = - Settings.Secure.putStringForUser(getContext().getContentResolver(), + Settings.Secure.putStringForUser( + getContext().getContentResolver(), Settings.Secure.CREDENTIAL_SERVICE, - String.join(":", enableProvider), + String.join(":", enabledProviders), userId); boolean writePrimaryStatus = - Settings.Secure.putStringForUser(getContext().getContentResolver(), + Settings.Secure.putStringForUser( + getContext().getContentResolver(), Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, String.join(":", primaryProviders), userId); @@ -827,15 +850,13 @@ public final class CredentialManagerService Slog.e(TAG, "Failed to store setting containing enabled or primary providers"); try { MetricUtilities.logApiCalledSimpleV2( - ApiName.SET_ENABLED_PROVIDERS, - ApiStatus.FAILURE, callingUid); + ApiName.SET_ENABLED_PROVIDERS, ApiStatus.FAILURE, callingUid); callback.onError( "failed_setting_store", "Failed to store setting containing enabled or primary providers"); } catch (RemoteException e) { MetricUtilities.logApiCalledSimpleV2( - ApiName.SET_ENABLED_PROVIDERS, - ApiStatus.FAILURE, callingUid); + ApiName.SET_ENABLED_PROVIDERS, ApiStatus.FAILURE, callingUid); Slog.e(TAG, "Issue with invoking error response: ", e); return; } @@ -844,13 +865,11 @@ public final class CredentialManagerService // Call the callback. try { MetricUtilities.logApiCalledSimpleV2( - ApiName.SET_ENABLED_PROVIDERS, - ApiStatus.SUCCESS, callingUid); + ApiName.SET_ENABLED_PROVIDERS, ApiStatus.SUCCESS, callingUid); callback.onResponse(); } catch (RemoteException e) { MetricUtilities.logApiCalledSimpleV2( - ApiName.SET_ENABLED_PROVIDERS, - ApiStatus.FAILURE, callingUid); + ApiName.SET_ENABLED_PROVIDERS, ApiStatus.FAILURE, callingUid); Slog.e(TAG, "Issue with invoking response: ", e); // TODO: Propagate failure } @@ -859,8 +878,10 @@ public final class CredentialManagerService @Override public boolean isEnabledCredentialProviderService( ComponentName componentName, String callingPackage) { - Slog.i(TAG, "isEnabledCredentialProviderService with componentName: " - + componentName.flattenToString()); + Slog.i( + TAG, + "isEnabledCredentialProviderService with componentName: " + + componentName.flattenToString()); // TODO(253157366): Check additional set of services. final int userId = UserHandle.getCallingUserId(); @@ -877,7 +898,8 @@ public final class CredentialManagerService // The component name and the package name do not match. MetricUtilities.logApiCalledSimpleV2( ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, - ApiStatus.FAILURE, callingUid); + ApiStatus.FAILURE, + callingUid); Slog.w( TAG, "isEnabledCredentialProviderService: Component name does " @@ -886,7 +908,8 @@ public final class CredentialManagerService } MetricUtilities.logApiCalledSimpleV2( ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, - ApiStatus.SUCCESS, callingUid); + ApiStatus.SUCCESS, + callingUid); return true; } } @@ -901,13 +924,14 @@ public final class CredentialManagerService verifyGetProvidersPermission(); final int callingUid = Binder.getCallingUid(); MetricUtilities.logApiCalledSimpleV2( - ApiName.GET_CREDENTIAL_PROVIDER_SERVICES, - ApiStatus.SUCCESS, callingUid); - return CredentialProviderInfoFactory - .getCredentialProviderServices( - mContext, userId, providerFilter, getEnabledProvidersForUser(userId), - getPrimaryProvidersForUserId(mContext, userId)); + ApiName.GET_CREDENTIAL_PROVIDER_SERVICES, ApiStatus.SUCCESS, callingUid); + return CredentialProviderInfoFactory.getCredentialProviderServices( + mContext, + userId, + providerFilter, + getEnabledProvidersForUser(userId), + getPrimaryProvidersForUserId(mContext, userId)); } @Override @@ -917,7 +941,10 @@ public final class CredentialManagerService final int userId = UserHandle.getCallingUserId(); return CredentialProviderInfoFactory.getCredentialProviderServicesForTesting( - mContext, userId, providerFilter, getEnabledProvidersForUser(userId), + mContext, + userId, + providerFilter, + getEnabledProvidersForUser(userId), getPrimaryProvidersForUserId(mContext, userId)); } @@ -935,15 +962,22 @@ public final class CredentialManagerService } private Set<ComponentName> getEnabledProvidersForUser(int userId) { - final int resolvedUserId = ActivityManager.handleIncomingUser( - Binder.getCallingPid(), Binder.getCallingUid(), - userId, false, false, - "getEnabledProvidersForUser", null); + final int resolvedUserId = + ActivityManager.handleIncomingUser( + Binder.getCallingPid(), + Binder.getCallingUid(), + userId, + false, + false, + "getEnabledProvidersForUser", + null); Set<ComponentName> enabledProviders = new HashSet<>(); - String directValue = Settings.Secure.getStringForUser( - mContext.getContentResolver(), Settings.Secure.CREDENTIAL_SERVICE, - resolvedUserId); + String directValue = + Settings.Secure.getStringForUser( + mContext.getContentResolver(), + Settings.Secure.CREDENTIAL_SERVICE, + resolvedUserId); if (!TextUtils.isEmpty(directValue)) { String[] components = directValue.split(":"); @@ -964,8 +998,7 @@ public final class CredentialManagerService IClearCredentialStateCallback callback, String callingPackage) { final long timestampBegan = System.nanoTime(); - Slog.i(TAG, "starting clearCredentialState with callingPackage: " - + callingPackage); + Slog.i(TAG, "starting clearCredentialState with callingPackage: " + callingPackage); final int userId = UserHandle.getCallingUserId(); int callingUid = Binder.getCallingUid(); enforceCallingPackage(callingPackage, callingUid); @@ -996,13 +1029,13 @@ public final class CredentialManagerService if (providerSessions.isEmpty()) { try { // TODO("Replace with properly defined error type") - callback.onError("UNKNOWN", "No credentials available on " - + "this device"); + callback.onError("UNKNOWN", "No credentials available on " + "this device"); } catch (RemoteException e) { Slog.e( TAG, "Issue invoking onError on IClearCredentialStateCallback " - + "callback: ", e); + + "callback: ", + e); } } @@ -1035,9 +1068,7 @@ public final class CredentialManagerService public void unregisterCredentialDescription( UnregisterCredentialDescriptionRequest request, String callingPackage) throws IllegalArgumentException { - Slog.i(TAG, "unregisterCredentialDescription with callingPackage: " - + callingPackage); - + Slog.i(TAG, "unregisterCredentialDescription with callingPackage: " + callingPackage); if (!isCredentialDescriptionApiEnabled()) { throw new UnsupportedOperationException("Feature not supported"); @@ -1061,18 +1092,18 @@ public final class CredentialManagerService } private void enforcePermissionForAllowedProviders(GetCredentialRequest request) { - boolean containsAllowedProviders = request.getCredentialOptions() - .stream() - .anyMatch(option -> option.getAllowedProviders() != null - && !option.getAllowedProviders().isEmpty()); + boolean containsAllowedProviders = + request.getCredentialOptions().stream() + .anyMatch( + option -> + option.getAllowedProviders() != null + && !option.getAllowedProviders().isEmpty()); if (containsAllowedProviders) { - mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS, - null); + mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS, null); } } - private void addSessionLocked(@UserIdInt int userId, - RequestSession requestSession) { + private void addSessionLocked(@UserIdInt int userId, RequestSession requestSession) { synchronized (mLock) { mSessionManager.addSession(userId, requestSession.mRequestId, requestSession); } @@ -1080,11 +1111,11 @@ public final class CredentialManagerService private void enforceCallingPackage(String callingPackage, int callingUid) { int packageUid; - PackageManager pm = mContext.createContextAsUser( - UserHandle.getUserHandleForUid(callingUid), 0).getPackageManager(); + PackageManager pm = + mContext.createContextAsUser(UserHandle.getUserHandleForUid(callingUid), 0) + .getPackageManager(); try { - packageUid = pm.getPackageUid(callingPackage, - PackageManager.PackageInfoFlags.of(0)); + packageUid = pm.getPackageUid(callingPackage, PackageManager.PackageInfoFlags.of(0)); } catch (PackageManager.NameNotFoundException e) { throw new SecurityException(callingPackage + " not found"); } @@ -1110,4 +1141,72 @@ public final class CredentialManagerService mRequestSessions.get(userId).put(token, requestSession); } } + + /** Updates settings when packages are removed. */ + private final PackageMonitor mPackageMonitor = + new PackageMonitor() { + + @Override + public void onPackageRemoved(String packageName, int uid) { + Slog.d(TAG, "onPackageRemoved: " + packageName); + + // Remove any providers from the primary setting that contain the package name + // being removed. + Set<String> primaryProviders = + getStoredProviders( + Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, packageName); + if (!Settings.Secure.putString( + getContext().getContentResolver(), + Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, + String.join(":", primaryProviders))) { + Slog.w(TAG, "Failed to remove primary package: " + packageName); + return; + } + + // Get the secondary providers and if there are no primary providers then + // we should erase all the providers from the secondary list because the + // feature is now disabled. + if (!primaryProviders.isEmpty()) { + return; + } + + if (!Settings.Secure.putString( + getContext().getContentResolver(), + Settings.Secure.CREDENTIAL_SERVICE, + "")) { + Slog.w(TAG, "Failed to remove secondary package: " + packageName); + return; + } + } + + private Set<String> getStoredProviders(String key, String packageName) { + // Get the current providers. + String rawProviders = + Settings.Secure.getStringForUser( + getContext().getContentResolver(), key, + UserHandle.myUserId()); + if (rawProviders == null) { + Slog.w(TAG, "settings key is null: " + key); + return new HashSet<>(); + } + + // If the app being removed matches any of the package names from + // this list then don't add it in the output. + Set<String> providers = new HashSet<>(); + for (String rawComponentName : rawProviders.split(":")) { + if (TextUtils.isEmpty(rawComponentName) + || rawComponentName.equals("null")) { + Slog.d(TAG, "provider component name is empty or null"); + continue; + } + + ComponentName cn = ComponentName.unflattenFromString(rawComponentName); + if (cn != null && !cn.getPackageName().equals(packageName)) { + providers.add(cn.flattenToString()); + } + } + + return providers; + } + }; } diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java index b90f08e420e7..3c190bf7ad11 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java @@ -32,6 +32,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.ResultReceiver; +import android.os.UserHandle; import android.service.credentials.CredentialProviderInfoFactory; import android.util.Slog; @@ -171,7 +172,9 @@ public class CredentialManagerUi { .setAction(UUID.randomUUID().toString()); //TODO: Create unique pending intent using request code and cancel any pre-existing pending // intents - return PendingIntent.getActivity( - mContext, /*requestCode=*/0, intent, PendingIntent.FLAG_IMMUTABLE); + return PendingIntent.getActivityAsUser( + mContext, /*requestCode=*/0, intent, + PendingIntent.FLAG_IMMUTABLE, /*options=*/null, + UserHandle.of(mUserId)); } } diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java index 3eb6718c0a95..7bd1cc4ca6c8 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java @@ -31,6 +31,7 @@ import android.credentials.ui.Entry; import android.credentials.ui.GetCredentialProviderData; import android.credentials.ui.ProviderPendingIntentResponse; import android.os.ICancellationSignal; +import android.service.autofill.Flags; import android.service.credentials.Action; import android.service.credentials.BeginGetCredentialOption; import android.service.credentials.BeginGetCredentialRequest; @@ -42,6 +43,7 @@ import android.service.credentials.GetCredentialRequest; import android.service.credentials.RemoteEntry; import android.util.Pair; import android.util.Slog; +import android.view.autofill.AutofillId; import java.util.ArrayList; import java.util.HashMap; @@ -379,13 +381,23 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential // but does not resolve to a valid option. For now, not skipping it because // it may be possible that the provider adds their own extras and expects to receive // those and complete the flow. - if (mBeginGetOptionToCredentialOptionMap.get(id) == null) { + Intent intent = new Intent(); + CredentialOption credentialOption = mBeginGetOptionToCredentialOptionMap.get(id); + if (credentialOption == null) { Slog.w(TAG, "Id from Credential Entry does not resolve to a valid option"); - return new Intent(); + return intent; } - return new Intent().putExtra(CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST, + AutofillId autofillId = credentialOption + .getCandidateQueryData() + .getParcelable(CredentialProviderService.EXTRA_AUTOFILL_ID, AutofillId.class); + if (autofillId != null && Flags.autofillCredmanIntegration()) { + intent.putExtra(CredentialProviderService.EXTRA_AUTOFILL_ID, autofillId); + } + return intent.putExtra( + CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST, new GetCredentialRequest( - mCallingAppInfo, List.of(mBeginGetOptionToCredentialOptionMap.get(id)))); + mCallingAppInfo, + List.of(credentialOption))); } private Intent setUpFillInIntentWithQueryRequest() { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java index 16876ac64e71..eb893fcfee1f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java @@ -251,7 +251,14 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { private int runSetDeviceOwner(PrintWriter pw) { parseArgs(); - mService.setActiveAdmin(mComponent, /* refreshing= */ true, mUserId); + boolean isAdminAdded = false; + try { + mService.setActiveAdmin(mComponent, /* refreshing= */ false, mUserId); + isAdminAdded = true; + } catch (IllegalArgumentException e) { + pw.printf("%s was already an admin for user %d. No need to set it again.\n", + mComponent.flattenToShortString(), mUserId); + } try { if (!mService.setDeviceOwner(mComponent, mUserId, @@ -260,8 +267,10 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { "Can't set package " + mComponent + " as device owner."); } } catch (Exception e) { - // Need to remove the admin that we just added. - mService.removeActiveAdmin(mComponent, UserHandle.USER_SYSTEM); + if (isAdminAdded) { + // Need to remove the admin that we just added. + mService.removeActiveAdmin(mComponent, mUserId); + } throw e; } diff --git a/services/foldables/devicestateprovider/tests/Android.bp b/services/foldables/devicestateprovider/tests/Android.bp index a8db05e99179..84a6df38e0a0 100644 --- a/services/foldables/devicestateprovider/tests/Android.bp +++ b/services/foldables/devicestateprovider/tests/Android.bp @@ -20,11 +20,11 @@ android_test { "foldable-device-state-provider", "androidx.test.rules", "junit", - "truth-prebuilt", + "truth", "mockito-target-extended-minus-junit4", "androidx.test.uiautomator_uiautomator", "androidx.test.ext.junit", "testables", ], - test_suites: ["device-tests"] + test_suites: ["device-tests"], } diff --git a/services/robotests/backup/Android.bp b/services/robotests/backup/Android.bp index e04dd688f2a2..8b9efb312efe 100644 --- a/services/robotests/backup/Android.bp +++ b/services/robotests/backup/Android.bp @@ -59,7 +59,7 @@ android_robolectric_test { "mockito-robolectric-prebuilt", "platform-test-annotations", "testng", - "truth-prebuilt", + "truth", ], instrumentation_for: "BackupFrameworksServicesLib", diff --git a/services/tests/InputMethodSystemServerTests/Android.bp b/services/tests/InputMethodSystemServerTests/Android.bp index 36446f64bdce..ffe6dc5d1c63 100644 --- a/services/tests/InputMethodSystemServerTests/Android.bp +++ b/services/tests/InputMethodSystemServerTests/Android.bp @@ -44,7 +44,7 @@ android_test { "service-permission.stubs.system_server", "servicestests-core-utils", "servicestests-utils-mockito-extended", - "truth-prebuilt", + "truth", ], libs: [ @@ -92,7 +92,7 @@ android_test { "service-permission.stubs.system_server", "servicestests-core-utils", "servicestests-utils-mockito-extended", - "truth-prebuilt", + "truth", "SimpleImeTestingLib", "SimpleImeImsLib", ], diff --git a/services/tests/PackageManager/packageinstaller/Android.bp b/services/tests/PackageManager/packageinstaller/Android.bp index 35d754b4adc5..e8fce8e72601 100644 --- a/services/tests/PackageManager/packageinstaller/Android.bp +++ b/services/tests/PackageManager/packageinstaller/Android.bp @@ -32,7 +32,7 @@ android_test { "androidx.test.runner", "junit", "kotlin-test", - "truth-prebuilt", + "truth", ], platform_apis: true, test_suites: ["device-tests"], diff --git a/services/tests/PackageManagerComponentOverrideTests/Android.bp b/services/tests/PackageManagerComponentOverrideTests/Android.bp index bc369701b2d4..00850a5e5be0 100644 --- a/services/tests/PackageManagerComponentOverrideTests/Android.bp +++ b/services/tests/PackageManagerComponentOverrideTests/Android.bp @@ -38,7 +38,7 @@ android_test { "service-permission.stubs.system_server", "servicestests-utils-mockito-extended", "testng", // TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows - "truth-prebuilt", + "truth", ], jni_libs: [ diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp index 9c4e6fd66ceb..ad7af44d4089 100644 --- a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp +++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp @@ -29,7 +29,7 @@ android_test { static_libs: [ "compatibility-device-util-axt", "androidx.test.runner", - "truth-prebuilt", + "truth", "Harrier", ], platform_apis: true, diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp index ce28682c0a25..6eacef767042 100644 --- a/services/tests/PackageManagerServiceTests/host/Android.bp +++ b/services/tests/PackageManagerServiceTests/host/Android.bp @@ -30,7 +30,7 @@ java_test_host { libs: [ "tradefed", "junit", - "truth-prebuilt", + "truth", ], static_libs: [ "ApexInstallHelper", diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp index 462c5801e952..cea9c599317d 100644 --- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp +++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp @@ -38,6 +38,6 @@ android_test_helper_app { "junit-params", "androidx.test.ext.junit", "androidx.test.rules", - "truth-prebuilt", + "truth", ], } diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp index 57184748d074..ed5f2b51b9ed 100644 --- a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp +++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp @@ -28,6 +28,6 @@ android_test_helper_app { "androidx.test.runner", "junit", "kotlin-test", - "truth-prebuilt", + "truth", ], } diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp index a1d846e0f426..3aca1cafbf75 100644 --- a/services/tests/PackageManagerServiceTests/server/Android.bp +++ b/services/tests/PackageManagerServiceTests/server/Android.bp @@ -41,7 +41,7 @@ android_test { "mockito-target-minus-junit4", "platform-test-annotations", "ShortcutManagerTestUtils", - "truth-prebuilt", + "truth", "testables", "platformprotosnano", "framework-protos", @@ -51,7 +51,7 @@ android_test { "servicestests-utils", "service-permission.impl", "testng", - "truth-prebuilt", + "truth", "junit", "junit-params", "platform-compat-test-rules", diff --git a/services/tests/PackageManagerServiceTests/unit/Android.bp b/services/tests/PackageManagerServiceTests/unit/Android.bp index 9b3b8c35736c..8505983894a8 100644 --- a/services/tests/PackageManagerServiceTests/unit/Android.bp +++ b/services/tests/PackageManagerServiceTests/unit/Android.bp @@ -37,7 +37,7 @@ android_test { "services.core", "servicestests-utils", "servicestests-core-utils", - "truth-prebuilt", + "truth", ], jni_libs: [ "libdexmakerjvmtiagent", diff --git a/services/tests/RemoteProvisioningServiceTests/Android.bp b/services/tests/RemoteProvisioningServiceTests/Android.bp index fc2c0857146b..19c913620760 100644 --- a/services/tests/RemoteProvisioningServiceTests/Android.bp +++ b/services/tests/RemoteProvisioningServiceTests/Android.bp @@ -30,8 +30,8 @@ android_test { "mockito-target", "service-rkp.impl", "services.core", - "truth-prebuilt", - "truth-java8-extension-jar", + "truth", + "truth-java8-extension", ], test_suites: [ "device-tests", diff --git a/services/tests/apexsystemservices/Android.bp b/services/tests/apexsystemservices/Android.bp index e724e804f4e7..9dacfeabf1ef 100644 --- a/services/tests/apexsystemservices/Android.bp +++ b/services/tests/apexsystemservices/Android.bp @@ -34,7 +34,7 @@ java_test_host { "compatibility-host-util", "cts-install-lib-host", "frameworks-base-hostutils", - "truth-prebuilt", + "truth", "modules-utils-build-testing", ], test_suites: [ diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java index 6ef150c80037..c37d21ae1cc0 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java @@ -179,6 +179,89 @@ public final class DisplayDeviceConfigTest { } @Test + public void testPowerThrottlingConfigFromDisplayConfig() throws IOException { + setupDisplayDeviceConfigFromDisplayConfigFile(); + + DisplayDeviceConfig.PowerThrottlingConfigData powerThrottlingConfigData = + mDisplayDeviceConfig.getPowerThrottlingConfigData(); + assertNotNull(powerThrottlingConfigData); + assertEquals(0.1f, powerThrottlingConfigData.brightnessLowestCapAllowed, SMALL_DELTA); + assertEquals(10, powerThrottlingConfigData.pollingWindowMillis); + } + + @Test + public void testPowerThrottlingDataFromDisplayConfig() throws IOException { + setupDisplayDeviceConfigFromDisplayConfigFile(); + + List<DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel> + defaultThrottlingLevels = new ArrayList<>(); + defaultThrottlingLevels.add( + new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( + DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 800f + )); + defaultThrottlingLevels.add( + new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( + DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 600f + )); + defaultThrottlingLevels.add( + new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( + DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 400f + )); + defaultThrottlingLevels.add( + new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( + DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 200f + )); + defaultThrottlingLevels.add( + new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( + DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 100f + )); + defaultThrottlingLevels.add( + new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( + DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 50f + )); + + DisplayDeviceConfig.PowerThrottlingData defaultThrottlingData = + new DisplayDeviceConfig.PowerThrottlingData(defaultThrottlingLevels); + + List<DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel> + concurrentThrottlingLevels = new ArrayList<>(); + concurrentThrottlingLevels.add( + new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( + DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 800f + )); + concurrentThrottlingLevels.add( + new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( + DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 600f + )); + concurrentThrottlingLevels.add( + new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( + DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 400f + )); + concurrentThrottlingLevels.add( + new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( + DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 200f + )); + concurrentThrottlingLevels.add( + new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( + DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 100f + )); + concurrentThrottlingLevels.add( + new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( + DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 50f + )); + DisplayDeviceConfig.PowerThrottlingData concurrentThrottlingData = + new DisplayDeviceConfig.PowerThrottlingData(concurrentThrottlingLevels); + + HashMap<String, DisplayDeviceConfig.PowerThrottlingData> throttlingDataMap = + new HashMap<>(2); + throttlingDataMap.put("default", defaultThrottlingData); + throttlingDataMap.put("concurrent", concurrentThrottlingData); + + assertEquals(throttlingDataMap, + mDisplayDeviceConfig.getPowerThrottlingDataMapByThrottlingId()); + } + + @Test public void testConfigValuesFromConfigResource() { setupDisplayDeviceConfigFromConfigResourceFile(); verifyConfigValuesFromConfigResource(); @@ -845,6 +928,64 @@ public final class DisplayDeviceConfigTest { + "</screenBrightnessRampSlowIncreaseIdle>\n"; } + private String getPowerThrottlingConfig() { + return "<powerThrottlingConfig >\n" + + "<brightnessLowestCapAllowed>0.1</brightnessLowestCapAllowed>\n" + + "<pollingWindowMillis>10</pollingWindowMillis>\n" + + "<powerThrottlingMap>\n" + + "<powerThrottlingPoint>\n" + + "<thermalStatus>light</thermalStatus>\n" + + "<powerQuotaMilliWatts>800</powerQuotaMilliWatts>\n" + + "</powerThrottlingPoint>\n" + + "<powerThrottlingPoint>\n" + + "<thermalStatus>moderate</thermalStatus>\n" + + "<powerQuotaMilliWatts>600</powerQuotaMilliWatts>\n" + + "</powerThrottlingPoint>\n" + + "<powerThrottlingPoint>\n" + + "<thermalStatus>severe</thermalStatus>\n" + + "<powerQuotaMilliWatts>400</powerQuotaMilliWatts>\n" + + "</powerThrottlingPoint>\n" + + "<powerThrottlingPoint>\n" + + "<thermalStatus>critical</thermalStatus>\n" + + "<powerQuotaMilliWatts>200</powerQuotaMilliWatts>\n" + + "</powerThrottlingPoint>\n" + + "<powerThrottlingPoint>\n" + + "<thermalStatus>emergency</thermalStatus>\n" + + "<powerQuotaMilliWatts>100</powerQuotaMilliWatts>\n" + + "</powerThrottlingPoint>\n" + + "<powerThrottlingPoint>\n" + + "<thermalStatus>shutdown</thermalStatus>\n" + + "<powerQuotaMilliWatts>50</powerQuotaMilliWatts>\n" + + "</powerThrottlingPoint>\n" + + "</powerThrottlingMap>\n" + + "<powerThrottlingMap id=\"concurrent\">\n" + + "<powerThrottlingPoint>\n" + + "<thermalStatus>light</thermalStatus>\n" + + "<powerQuotaMilliWatts>800</powerQuotaMilliWatts>\n" + + "</powerThrottlingPoint>\n" + + "<powerThrottlingPoint>\n" + + "<thermalStatus>moderate</thermalStatus>\n" + + "<powerQuotaMilliWatts>600</powerQuotaMilliWatts>\n" + + "</powerThrottlingPoint>\n" + + "<powerThrottlingPoint>\n" + + "<thermalStatus>severe</thermalStatus>\n" + + "<powerQuotaMilliWatts>400</powerQuotaMilliWatts>\n" + + "</powerThrottlingPoint>\n" + + "<powerThrottlingPoint>\n" + + "<thermalStatus>critical</thermalStatus>\n" + + "<powerQuotaMilliWatts>200</powerQuotaMilliWatts>\n" + + "</powerThrottlingPoint>\n" + + "<powerThrottlingPoint>\n" + + "<thermalStatus>emergency</thermalStatus>\n" + + "<powerQuotaMilliWatts>100</powerQuotaMilliWatts>\n" + + "</powerThrottlingPoint>\n" + + "<powerThrottlingPoint>\n" + + "<thermalStatus>shutdown</thermalStatus>\n" + + "<powerQuotaMilliWatts>50</powerQuotaMilliWatts>\n" + + "</powerThrottlingPoint>\n" + + "</powerThrottlingMap>\n" + + "</powerThrottlingConfig>\n"; + } private String getScreenBrightnessRampCapsIdle() { return "<screenBrightnessRampIncreaseMaxIdleMillis>" + "4000" @@ -915,6 +1056,7 @@ public final class DisplayDeviceConfigTest { + "</displayBrightnessPoint>\n" + "</displayBrightnessMapping>\n" + "</autoBrightness>\n" + + getPowerThrottlingConfig() + "<highBrightnessMode enabled=\"true\">\n" + "<transitionPoint>" + BRIGHTNESS[1] + "</transitionPoint>\n" + "<minimumLux>10000</minimumLux>\n" diff --git a/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java new file mode 100644 index 000000000000..5c50acb13f30 --- /dev/null +++ b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java @@ -0,0 +1,85 @@ +/* + * 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 com.android.server.display; + +import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; + +import android.hardware.display.DisplayManager; +import android.testing.TestableContext; +import android.view.Display; + +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.display.RefreshRateSettingsUtils; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class RefreshRateSettingsUtilsTest { + + @Rule + public final TestableContext mContext = new TestableContext( + InstrumentationRegistry.getInstrumentation().getContext()); + + @Mock + private DisplayManager mDisplayManagerMock; + @Mock + private Display mDisplayMock; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext.addMockSystemService(DisplayManager.class, mDisplayManagerMock); + + Display.Mode[] modes = new Display.Mode[]{ + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 60), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 120), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 90) + }; + + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); + when(mDisplayMock.getSupportedModes()).thenReturn(modes); + } + + @Test + public void testFindHighestRefreshRateForDefaultDisplay() { + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null); + assertEquals(DEFAULT_REFRESH_RATE, + RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext), + /* delta= */ 0); + + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); + assertEquals(120, + RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext), + /* delta= */ 0); + } +} diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java index c63fac9832e9..ee187baf524e 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java @@ -22,6 +22,9 @@ import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -97,6 +100,37 @@ public class HdrClamperTest { } @Test + public void testRegisterHdrListener() { + verify(mMockHdrInfoListener).register(mMockBinder); + } + + @Test + public void testRegisterOtherHdrListenerWhenCalledWithOtherToken() { + IBinder otherBinder = mock(IBinder.class); + mHdrClamper.resetHdrConfig(TEST_HDR_DATA, WIDTH, HEIGHT, MIN_HDR_PERCENT, otherBinder); + + verify(mMockHdrInfoListener).unregister(mMockBinder); + verify(mMockHdrInfoListener).register(otherBinder); + } + + @Test + public void testRegisterHdrListenerOnceWhenCalledWithSameToken() { + mHdrClamper.resetHdrConfig(TEST_HDR_DATA, WIDTH, HEIGHT, MIN_HDR_PERCENT, mMockBinder); + + verify(mMockHdrInfoListener, never()).unregister(mMockBinder); + verify(mMockHdrInfoListener, times(1)).register(mMockBinder); + } + + @Test + public void testRegisterNotCalledIfHbmConfigIsMissing() { + IBinder otherBinder = mock(IBinder.class); + mHdrClamper.resetHdrConfig(TEST_HDR_DATA, WIDTH, HEIGHT, -1, otherBinder); + + verify(mMockHdrInfoListener).unregister(mMockBinder); + verify(mMockHdrInfoListener, never()).register(otherBinder); + } + + @Test public void testClamper_AmbientLuxChangesAboveLimit() { mHdrClamper.onAmbientLuxChange(500); diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java index b8c18e070397..c4f72b307eb7 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java @@ -27,6 +27,7 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_R import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE; import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.server.display.mode.Vote.INVALID_SIZE; import static com.google.common.truth.Truth.assertThat; @@ -85,10 +86,12 @@ import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.internal.display.BrightnessSynchronizer; +import com.android.internal.display.RefreshRateSettingsUtils; import com.android.internal.os.BackgroundThread; import com.android.internal.util.Preconditions; import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.util.test.FakeSettingsProviderRule; +import com.android.modules.utils.testing.ExtendedMockitoRule; import com.android.server.display.DisplayDeviceConfig; import com.android.server.display.TestUtils; import com.android.server.display.feature.DisplayManagerFlags; @@ -106,7 +109,7 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; +import org.mockito.quality.Strictness; import org.mockito.stubbing.Answer; import java.util.ArrayList; @@ -252,9 +255,15 @@ public class DisplayModeDirectorTest { @Mock private DisplayManagerFlags mDisplayManagerFlags; + @Rule + public final ExtendedMockitoRule mExtendedMockitoRule = + new ExtendedMockitoRule.Builder(this) + .setStrictness(Strictness.LENIENT) + .spyStatic(RefreshRateSettingsUtils.class) + .build(); + @Before public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext); when(mContext.getContentResolver()).thenReturn(resolver); @@ -1470,6 +1479,94 @@ public class DisplayModeDirectorTest { } @Test + public void testPeakRefreshRate_FlagEnabled() { + when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) + .thenReturn(true); + float highestRefreshRate = 130; + doReturn(highestRefreshRate).when(() -> + RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext)); + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0); + director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); + + Sensor lightSensor = createLightSensor(); + SensorManager sensorManager = createMockSensorManager(lightSensor); + director.start(sensorManager); + + setPeakRefreshRate(Float.POSITIVE_INFINITY); + + Vote vote = director.getVote(Display.DEFAULT_DISPLAY, + Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); + assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ + highestRefreshRate); + } + + @Test + public void testPeakRefreshRate_FlagDisabled() { + when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) + .thenReturn(false); + float peakRefreshRate = 130; + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0); + director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); + + Sensor lightSensor = createLightSensor(); + SensorManager sensorManager = createMockSensorManager(lightSensor); + director.start(sensorManager); + + setPeakRefreshRate(peakRefreshRate); + + Vote vote = director.getVote(Display.DEFAULT_DISPLAY, + Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); + assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ + peakRefreshRate); + } + + @Test + public void testMinRefreshRate_FlagEnabled() { + when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) + .thenReturn(true); + float highestRefreshRate = 130; + doReturn(highestRefreshRate).when(() -> + RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext)); + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0); + director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); + + Sensor lightSensor = createLightSensor(); + SensorManager sensorManager = createMockSensorManager(lightSensor); + director.start(sensorManager); + + setMinRefreshRate(Float.POSITIVE_INFINITY); + + Vote vote = director.getVote(Display.DEFAULT_DISPLAY, + Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); + assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate, + /* frameRateHigh= */ Float.POSITIVE_INFINITY); + } + + @Test + public void testMinRefreshRate_FlagDisabled() { + when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) + .thenReturn(false); + float minRefreshRate = 130; + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0); + director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); + + Sensor lightSensor = createLightSensor(); + SensorManager sensorManager = createMockSensorManager(lightSensor); + director.start(sensorManager); + + setMinRefreshRate(minRefreshRate); + + Vote vote = director.getVote(Display.DEFAULT_DISPLAY, + Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); + assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ minRefreshRate, + /* frameRateHigh= */ Float.POSITIVE_INFINITY); + } + + @Test public void testSensorRegistration() { // First, configure brightness zones or DMD won't register for sensor data. final FakeDeviceConfig config = mInjector.getDeviceConfig(); @@ -3167,6 +3264,13 @@ public class DisplayModeDirectorTest { waitForIdleSync(); } + private void setMinRefreshRate(float fps) { + Settings.System.putFloat(mContext.getContentResolver(), Settings.System.MIN_REFRESH_RATE, + fps); + mInjector.notifyMinRefreshRateChanged(); + waitForIdleSync(); + } + private static SensorManager createMockSensorManager(Sensor... sensors) { SensorManager sensorManager = mock(SensorManager.class); when(sensorManager.getSensorList(anyInt())).then((invocation) -> { @@ -3216,6 +3320,7 @@ public class DisplayModeDirectorTest { private final SensorManagerInternal mSensorManagerInternal; private ContentObserver mPeakRefreshRateObserver; + private ContentObserver mMinRefreshRateObserver; FakesInjector() { this(null, null, null); @@ -3247,6 +3352,12 @@ public class DisplayModeDirectorTest { } @Override + public void registerMinRefreshRateObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer) { + mMinRefreshRateObserver = observer; + } + + @Override public void registerDisplayListener(DisplayListener listener, Handler handler) {} @Override @@ -3318,5 +3429,12 @@ public class DisplayModeDirectorTest { PEAK_REFRESH_RATE_URI); } } + + void notifyMinRefreshRateChanged() { + if (mMinRefreshRateObserver != null) { + mMinRefreshRateObserver.dispatchChange(false /*selfChange*/, + MIN_REFRESH_RATE_URI); + } + } } } diff --git a/services/tests/inprocesstests/Android.bp b/services/tests/inprocesstests/Android.bp index 7c237ac6befb..086e84b86aca 100644 --- a/services/tests/inprocesstests/Android.bp +++ b/services/tests/inprocesstests/Android.bp @@ -14,7 +14,7 @@ android_test { "androidx.test.core", "androidx.test.rules", "services.core", - "truth-prebuilt", + "truth", "platform-test-annotations", ], test_suites: ["general-tests"], diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp index 0813bb09fd52..063af573e1f3 100644 --- a/services/tests/mockingservicestests/Android.bp +++ b/services/tests/mockingservicestests/Android.bp @@ -68,7 +68,7 @@ android_test { "servicestests-core-utils", "servicestests-utils-mockito-extended", "testables", - "truth-prebuilt", + "truth", // TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows "testng", "compatibility-device-util-axt", diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp index 8ab45070a017..18a4f0068909 100644 --- a/services/tests/powerstatstests/Android.bp +++ b/services/tests/powerstatstests/Android.bp @@ -16,7 +16,7 @@ android_test { "coretests-aidl", "platformprotosnano", "junit", - "truth-prebuilt", + "truth", "androidx.test.runner", "androidx.test.ext.junit", "androidx.test.ext.truth", diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index 71f7f577d038..2ece8c74420c 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -61,7 +61,7 @@ android_test { "mockito-target-minus-junit4", "platform-test-annotations", "ShortcutManagerTestUtils", - "truth-prebuilt", + "truth", "testables", "androidx.test.uiautomator_uiautomator", "platformprotosnano", @@ -72,7 +72,7 @@ android_test { // TODO: remove once Android migrates to JUnit 4.12, // which provides assertThrows "testng", - "truth-prebuilt", + "truth", "junit", "junit-params", "ActivityContext", diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java index 61b30a024478..e8cbcf9a6874 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java @@ -233,6 +233,7 @@ public class VirtualDeviceManagerServiceTest { private VirtualDeviceManagerService mVdms; private VirtualDeviceManagerInternal mLocalService; private VirtualDeviceManagerService.VirtualDeviceManagerImpl mVdm; + private VirtualDeviceManagerService.VirtualDeviceManagerNativeImpl mVdmNative; private VirtualDeviceLog mVirtualDeviceLog; @Mock private InputController.NativeWrapper mNativeWrapperMock; @@ -340,6 +341,7 @@ public class VirtualDeviceManagerServiceTest { mSetFlagsRule.disableFlags(Flags.FLAG_DYNAMIC_POLICY); mSetFlagsRule.disableFlags(Flags.FLAG_STREAM_PERMISSIONS); mSetFlagsRule.disableFlags(Flags.FLAG_VDM_CUSTOM_HOME); + mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_NATIVE_VDM); doReturn(true).when(mInputManagerInternalMock).setVirtualMousePointerDisplayId(anyInt()); doNothing().when(mInputManagerInternalMock).setPointerAcceleration(anyFloat(), anyInt()); @@ -384,6 +386,7 @@ public class VirtualDeviceManagerServiceTest { mVdms = new VirtualDeviceManagerService(mContext); mLocalService = mVdms.getLocalServiceInstance(); mVdm = mVdms.new VirtualDeviceManagerImpl(); + mVdmNative = mVdms.new VirtualDeviceManagerNativeImpl(); mVirtualDeviceLog = new VirtualDeviceLog(mContext); mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1); mSensorController = mDeviceImpl.getSensorControllerForTest(); @@ -440,24 +443,32 @@ public class VirtualDeviceManagerServiceTest { public void getDevicePolicy_invalidDeviceId_returnsDefault() { assertThat(mVdm.getDevicePolicy(DEVICE_ID_INVALID, POLICY_TYPE_SENSORS)) .isEqualTo(DEVICE_POLICY_DEFAULT); + assertThat(mVdmNative.getDevicePolicy(DEVICE_ID_INVALID, POLICY_TYPE_SENSORS)) + .isEqualTo(DEVICE_POLICY_DEFAULT); } @Test public void getDevicePolicy_defaultDeviceId_returnsDefault() { assertThat(mVdm.getDevicePolicy(DEVICE_ID_DEFAULT, POLICY_TYPE_SENSORS)) .isEqualTo(DEVICE_POLICY_DEFAULT); + assertThat(mVdmNative.getDevicePolicy(DEVICE_ID_DEFAULT, POLICY_TYPE_SENSORS)) + .isEqualTo(DEVICE_POLICY_DEFAULT); } @Test public void getDevicePolicy_nonExistentDeviceId_returnsDefault() { assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId() + 1, POLICY_TYPE_SENSORS)) .isEqualTo(DEVICE_POLICY_DEFAULT); + assertThat(mVdmNative.getDevicePolicy(mDeviceImpl.getDeviceId() + 1, POLICY_TYPE_SENSORS)) + .isEqualTo(DEVICE_POLICY_DEFAULT); } @Test public void getDevicePolicy_unspecifiedPolicy_returnsDefault() { assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS)) .isEqualTo(DEVICE_POLICY_DEFAULT); + assertThat(mVdmNative.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS)) + .isEqualTo(DEVICE_POLICY_DEFAULT); } @Test @@ -472,6 +483,8 @@ public class VirtualDeviceManagerServiceTest { assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS)) .isEqualTo(DEVICE_POLICY_CUSTOM); + assertThat(mVdmNative.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS)) + .isEqualTo(DEVICE_POLICY_CUSTOM); } @Test @@ -567,8 +580,8 @@ public class VirtualDeviceManagerServiceTest { @Test public void getDeviceIdsForUid_noRunningApps_returnsNull() { - Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); - assertThat(deviceIds).isEmpty(); + assertThat(mLocalService.getDeviceIdsForUid(UID_1)).isEmpty(); + assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).isEmpty(); } @Test @@ -577,8 +590,8 @@ public class VirtualDeviceManagerServiceTest { mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged( Sets.newArraySet(UID_2)); - Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); - assertThat(deviceIds).isEmpty(); + assertThat(mLocalService.getDeviceIdsForUid(UID_1)).isEmpty(); + assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).isEmpty(); } @Test @@ -587,8 +600,9 @@ public class VirtualDeviceManagerServiceTest { mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged( Sets.newArraySet(UID_1)); - Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); - assertThat(deviceIds).containsExactly(mDeviceImpl.getDeviceId()); + int deviceId = mDeviceImpl.getDeviceId(); + assertThat(mLocalService.getDeviceIdsForUid(UID_1)).containsExactly(deviceId); + assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).asList().containsExactly(deviceId); } @Test @@ -598,8 +612,9 @@ public class VirtualDeviceManagerServiceTest { mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged( Sets.newArraySet(UID_1, UID_2)); - Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); - assertThat(deviceIds).containsExactly(mDeviceImpl.getDeviceId()); + int deviceId = mDeviceImpl.getDeviceId(); + assertThat(mLocalService.getDeviceIdsForUid(UID_1)).containsExactly(deviceId); + assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).asList().containsExactly(deviceId); } @Test @@ -611,8 +626,9 @@ public class VirtualDeviceManagerServiceTest { secondDevice.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_2).onRunningAppsChanged( Sets.newArraySet(UID_1)); - Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); - assertThat(deviceIds).containsExactly(secondDevice.getDeviceId()); + int deviceId = secondDevice.getDeviceId(); + assertThat(mLocalService.getDeviceIdsForUid(UID_1)).containsExactly(deviceId); + assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).asList().containsExactly(deviceId); } @Test @@ -628,8 +644,9 @@ public class VirtualDeviceManagerServiceTest { secondDevice.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_2).onRunningAppsChanged( Sets.newArraySet(UID_1, UID_2)); - Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1); - assertThat(deviceIds).containsExactly( + assertThat(mLocalService.getDeviceIdsForUid(UID_1)).containsExactly( + mDeviceImpl.getDeviceId(), secondDevice.getDeviceId()); + assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).asList().containsExactly( mDeviceImpl.getDeviceId(), secondDevice.getDeviceId()); } diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java index 184c976b86bf..3de167e72ba0 100644 --- a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java +++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java @@ -336,7 +336,8 @@ public final class UpdatableFontDirTest { return new FontConfig(Collections.emptyList(), Collections.emptyList(), Collections.singletonList(new FontConfig.NamedFamilyList( - Collections.singletonList(family), "sans-serif")), 0, 1); + Collections.singletonList(family), "sans-serif")), + Collections.emptyList(), 0, 1); }; UpdatableFontDir dirForPreparation = new UpdatableFontDir( @@ -499,7 +500,8 @@ public final class UpdatableFontDirTest { Collections.emptyList(), Collections.emptyList(), Collections.singletonList(new FontConfig.NamedFamilyList( - Collections.singletonList(family), "sans-serif")), 0, 1); + Collections.singletonList(family), "sans-serif")), + Collections.emptyList(), 0, 1); }); dir.loadFontFileMap(); @@ -651,7 +653,8 @@ public final class UpdatableFontDirTest { FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE); return new FontConfig(Collections.emptyList(), Collections.emptyList(), Collections.singletonList(new FontConfig.NamedFamilyList( - Collections.singletonList(family), "sans-serif")), 0, 1); + Collections.singletonList(family), "sans-serif")), + Collections.emptyList(), 0, 1); }); dir.loadFontFileMap(); diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java index 9f75cf8d552e..253592c9a07d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java @@ -43,6 +43,7 @@ import android.annotation.UserIdInt; import android.app.PropertyInvalidatedCache; import android.content.pm.UserInfo; import android.content.pm.UserInfo.UserInfoFlag; +import android.multiuser.Flags; import android.os.Looper; import android.os.Parcel; import android.os.UserHandle; @@ -124,18 +125,34 @@ public class UserManagerServiceUserInfoTest { mUserManagerService.putUserInfo(data.info); - // Set a global and user restriction so they get written out to the user file. + //Local restrictions are written to the user specific files and global restrictions + // are written to the SYSTEM user file. setUserRestrictions(data.info.id, globalRestriction, localRestriction, true); ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(baos); mUserManagerService.writeUserLP(data, out); - byte[] bytes = baos.toByteArray(); + byte[] secondaryUserBytes = baos.toByteArray(); + baos.reset(); + + byte[] systemUserBytes = new byte[0]; + if (Flags.saveGlobalAndGuestRestrictionsOnSystemUserXmlReadOnly()) { + UserData systemUserData = new UserData(); + systemUserData.info = mUserManagerService.getUserInfo(UserHandle.USER_SYSTEM); + mUserManagerService.writeUserLP(systemUserData, baos); + systemUserBytes = baos.toByteArray(); + } // Clear the restrictions to see if they are properly read in from the user file. setUserRestrictions(data.info.id, globalRestriction, localRestriction, false); - mUserManagerService.readUserLP(data.info.id, new ByteArrayInputStream(bytes)); + //read the secondary and SYSTEM user file to fetch local/global device policy restrictions. + mUserManagerService.readUserLP(data.info.id, new ByteArrayInputStream(secondaryUserBytes)); + if (Flags.saveGlobalAndGuestRestrictionsOnSystemUserXmlReadOnly()) { + mUserManagerService.readUserLP(UserHandle.USER_SYSTEM, + new ByteArrayInputStream(systemUserBytes)); + } + assertTrue(mUserManagerService.hasUserRestrictionOnAnyUser(globalRestriction)); assertTrue(mUserManagerService.hasUserRestrictionOnAnyUser(localRestriction)); } diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp index 1d37f9da8d7a..d1f4961ab7e5 100644 --- a/services/tests/uiservicestests/Android.bp +++ b/services/tests/uiservicestests/Android.bp @@ -39,7 +39,7 @@ android_test { "hamcrest-library", "servicestests-utils", "testables", - "truth-prebuilt", + "truth", // TODO: remove once Android migrates to JUnit 4.12, // which provides assertThrows "testng", diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java index c05f81497e57..53ca704b6d86 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java @@ -23,9 +23,7 @@ import static android.service.notification.NotificationListenerService.Ranking.U import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; @@ -49,12 +47,10 @@ import android.graphics.drawable.Icon; import android.os.Binder; import android.os.Build; import android.os.IBinder; -import android.os.Parcel; import android.os.RemoteException; import android.os.UserHandle; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.Ranking; -import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.NotificationRankingUpdate; import android.service.notification.SnoozeCriterion; import android.service.notification.StatusBarNotification; @@ -158,81 +154,6 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { } } - // Tests parceling of NotificationRankingUpdate, and by extension, RankingMap and Ranking. - @Test - public void testRankingUpdate_parcel() { - NotificationRankingUpdate nru = generateUpdate(); - Parcel parcel = Parcel.obtain(); - nru.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - NotificationRankingUpdate nru1 = NotificationRankingUpdate.CREATOR.createFromParcel(parcel); - assertEquals(nru, nru1); - } - - // Tests parceling of RankingMap and RankingMap.equals - @Test - public void testRankingMap_parcel() { - RankingMap rmap = generateUpdate().getRankingMap(); - Parcel parcel = Parcel.obtain(); - rmap.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - RankingMap rmap1 = RankingMap.CREATOR.createFromParcel(parcel); - - detailedAssertEquals(rmap, rmap1); - assertEquals(rmap, rmap1); - } - - // Tests parceling of Ranking and Ranking.equals - @Test - public void testRanking_parcel() { - Ranking ranking = generateUpdate().getRankingMap().getRawRankingObject(mKeys[0]); - Parcel parcel = Parcel.obtain(); - ranking.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - Ranking ranking1 = new Ranking(parcel); - detailedAssertEquals("rankings differ: ", ranking, ranking1); - assertEquals(ranking, ranking1); - } - - // Tests NotificationRankingUpdate.equals(), and by extension, RankingMap and Ranking. - @Test - public void testRankingUpdate_equals() { - NotificationRankingUpdate nru = generateUpdate(); - NotificationRankingUpdate nru2 = generateUpdate(); - detailedAssertEquals(nru, nru2); - assertEquals(nru, nru2); - Ranking tweak = nru2.getRankingMap().getRawRankingObject(mKeys[0]); - tweak.populate( - tweak.getKey(), - tweak.getRank(), - !tweak.matchesInterruptionFilter(), // note the inversion here! - tweak.getLockscreenVisibilityOverride(), - tweak.getSuppressedVisualEffects(), - tweak.getImportance(), - tweak.getImportanceExplanation(), - tweak.getOverrideGroupKey(), - tweak.getChannel(), - (ArrayList) tweak.getAdditionalPeople(), - (ArrayList) tweak.getSnoozeCriteria(), - tweak.canShowBadge(), - tweak.getUserSentiment(), - tweak.isSuspended(), - tweak.getLastAudiblyAlertedMillis(), - tweak.isNoisy(), - (ArrayList) tweak.getSmartActions(), - (ArrayList) tweak.getSmartReplies(), - tweak.canBubble(), - tweak.isTextChanged(), - tweak.isConversation(), - tweak.getConversationShortcutInfo(), - tweak.getRankingAdjustment(), - tweak.isBubble(), - tweak.getProposedImportance(), - tweak.hasSensitiveContent() - ); - assertNotEquals(nru, nru2); - } - @Test public void testLegacyIcons_preM() { TestListenerService service = new TestListenerService(); @@ -275,7 +196,6 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { assertNull(n.largeIcon); } - // Test data private String[] mKeys = new String[] { "key", "key1", "key2", "key3", "key4"}; @@ -461,48 +381,6 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { } } - private void detailedAssertEquals(NotificationRankingUpdate a, NotificationRankingUpdate b) { - detailedAssertEquals(a.getRankingMap(), b.getRankingMap()); - } - - private void detailedAssertEquals(String comment, Ranking a, Ranking b) { - assertEquals(comment, a.getKey(), b.getKey()); - assertEquals(comment, a.getRank(), b.getRank()); - assertEquals(comment, a.matchesInterruptionFilter(), b.matchesInterruptionFilter()); - assertEquals(comment, a.getLockscreenVisibilityOverride(), b.getLockscreenVisibilityOverride()); - assertEquals(comment, a.getSuppressedVisualEffects(), b.getSuppressedVisualEffects()); - assertEquals(comment, a.getImportance(), b.getImportance()); - assertEquals(comment, a.getImportanceExplanation(), b.getImportanceExplanation()); - assertEquals(comment, a.getOverrideGroupKey(), b.getOverrideGroupKey()); - assertEquals(comment, a.getChannel(), b.getChannel()); - assertEquals(comment, a.getAdditionalPeople(), b.getAdditionalPeople()); - assertEquals(comment, a.getSnoozeCriteria(), b.getSnoozeCriteria()); - assertEquals(comment, a.canShowBadge(), b.canShowBadge()); - assertEquals(comment, a.getUserSentiment(), b.getUserSentiment()); - assertEquals(comment, a.isSuspended(), b.isSuspended()); - assertEquals(comment, a.getLastAudiblyAlertedMillis(), b.getLastAudiblyAlertedMillis()); - assertEquals(comment, a.isNoisy(), b.isNoisy()); - assertEquals(comment, a.getSmartReplies(), b.getSmartReplies()); - assertEquals(comment, a.canBubble(), b.canBubble()); - assertEquals(comment, a.isConversation(), b.isConversation()); - assertEquals(comment, a.getConversationShortcutInfo().getId(), - b.getConversationShortcutInfo().getId()); - assertActionsEqual(a.getSmartActions(), b.getSmartActions()); - assertEquals(a.getProposedImportance(), b.getProposedImportance()); - assertEquals(a.hasSensitiveContent(), b.hasSensitiveContent()); - } - - private void detailedAssertEquals(RankingMap a, RankingMap b) { - Ranking arank = new Ranking(); - Ranking brank = new Ranking(); - assertArrayEquals(a.getOrderedKeys(), b.getOrderedKeys()); - for (String key : a.getOrderedKeys()) { - a.getRanking(key, arank); - b.getRanking(key, brank); - detailedAssertEquals("ranking for key <" + key + ">", arank, brank); - } - } - public static class TestListenerService extends NotificationListenerService { private final IBinder binder = new LocalBinder(); public int targetSdk = 0; diff --git a/services/tests/voiceinteractiontests/Android.bp b/services/tests/voiceinteractiontests/Android.bp index e704ebf32270..744cb63f72b3 100644 --- a/services/tests/voiceinteractiontests/Android.bp +++ b/services/tests/voiceinteractiontests/Android.bp @@ -43,7 +43,7 @@ android_test { "services.soundtrigger", "servicestests-core-utils", "servicestests-utils-mockito-extended", - "truth-prebuilt", + "truth", ], libs: [ diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp index c2812a14a3eb..af39b2f027ee 100644 --- a/services/tests/wmtests/Android.bp +++ b/services/tests/wmtests/Android.bp @@ -57,12 +57,14 @@ android_test { "platform-test-annotations", "servicestests-utils", "testng", - "truth-prebuilt", + "truth", "testables", "hamcrest-library", "platform-compat-test-rules", "CtsSurfaceValidatorLib", "service-sdksandbox.impl", + "com.android.window.flags.window-aconfig-java", + "flag-junit", ], libs: [ diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml index 42e3383987d6..762e23c8e288 100644 --- a/services/tests/wmtests/AndroidManifest.xml +++ b/services/tests/wmtests/AndroidManifest.xml @@ -47,6 +47,8 @@ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"/> + <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/> + <uses-permission android:name="android.permission.MONITOR_INPUT"/> <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) --> <application android:debuggable="true" @@ -104,6 +106,11 @@ android:showWhenLocked="true" android:turnScreenOn="true" /> + <activity android:name="android.app.Activity" + android:exported="true" + android:showWhenLocked="true" + android:turnScreenOn="true" /> + <activity android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyActivity" android:exported="true"> diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java index 0a7bb00ce1c2..71098aa5e883 100644 --- a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java @@ -20,6 +20,7 @@ import static com.android.server.policy.PhoneWindowManager.DOUBLE_TAP_HOME_RECEN import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_ALL_APPS; import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_ASSIST; import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_NOTIFICATION_PANEL; +import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL; import android.platform.test.annotations.Presubmit; import android.view.KeyEvent; @@ -284,6 +285,16 @@ public class ShortcutLoggingTests extends ShortcutKeyTestBase { KeyboardLogEvent.APP_SWITCH, KeyEvent.KEYCODE_H, META_ON}}; } + @Keep + private static Object[][] shortPressOnSettingsTestArguments() { + // testName, testKeys, shortPressOnSettingsBehavior, expectedLogEvent, expectedKey, + // expectedModifierState + return new Object[][]{ + {"SETTINGS key -> Toggle Notification panel", new int[]{KeyEvent.KEYCODE_SETTINGS}, + SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL, + KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL, KeyEvent.KEYCODE_SETTINGS, 0}}; + } + @Before public void setUp() { setUpPhoneWindowManager(/*supportSettingsUpdate*/ true); @@ -294,6 +305,7 @@ public class ShortcutLoggingTests extends ShortcutKeyTestBase { mPhoneWindowManager.overrideEnableBugReportTrigger(true); mPhoneWindowManager.overrideStatusBarManagerInternal(); mPhoneWindowManager.overrideStartActivity(); + mPhoneWindowManager.overrideSendBroadcast(); mPhoneWindowManager.overrideUserSetupComplete(); mPhoneWindowManager.setupAssistForLaunch(); mPhoneWindowManager.overrideTogglePanel(); @@ -330,4 +342,15 @@ public class ShortcutLoggingTests extends ShortcutKeyTestBase { mPhoneWindowManager.assertShortcutLogged(VENDOR_ID, PRODUCT_ID, expectedLogEvent, expectedKey, expectedModifierState, "Failed while executing " + testName); } + + @Test + @Parameters(method = "shortPressOnSettingsTestArguments") + public void testShortPressOnSettings(String testName, int[] testKeys, + int shortPressOnSettingsBehavior, KeyboardLogEvent expectedLogEvent, int expectedKey, + int expectedModifierState) { + mPhoneWindowManager.overrideShortPressOnSettingsBehavior(shortPressOnSettingsBehavior); + sendKeyCombination(testKeys, 0 /* duration */); + mPhoneWindowManager.assertShortcutLogged(VENDOR_ID, PRODUCT_ID, expectedLogEvent, + expectedKey, expectedModifierState, "Failed while executing " + testName); + } } 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 ef28ffa7da8f..2244dbe8af98 100644 --- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java +++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java @@ -375,6 +375,10 @@ class TestPhoneWindowManager { mPhoneWindowManager.mDoubleTapOnHomeBehavior = behavior; } + void overrideShortPressOnSettingsBehavior(int behavior) { + mPhoneWindowManager.mShortPressOnSettingsBehavior = behavior; + } + void overrideCanStartDreaming(boolean canDream) { doReturn(canDream).when(mDreamManagerInternal).canStartDreaming(anyBoolean()); } @@ -484,6 +488,10 @@ class TestPhoneWindowManager { doNothing().when(mContext).startActivityAsUser(any(), any(), any()); } + void overrideSendBroadcast() { + doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); + } + void overrideUserSetupComplete() { doReturn(true).when(mPhoneWindowManager).isUserSetupComplete(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java new file mode 100644 index 000000000000..ac498397eb39 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java @@ -0,0 +1,217 @@ +/* + * Copyright 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 com.android.server.wm; + +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.app.Activity; +import android.app.Instrumentation; +import android.os.IBinder; +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.server.wm.BuildUtils; +import android.server.wm.CtsWindowInfoUtils; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.WindowManager; + +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.window.flags.Flags; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@Presubmit +public class TrustedOverlayTests { + private static final String TAG = "TrustedOverlayTests"; + private static final long TIMEOUT_S = 5L * BuildUtils.HW_TIMEOUT_MULTIPLIER; + + @Rule + public final CheckFlagsRule mCheckFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule(); + + @Rule + public TestName mName = new TestName(); + + @Rule + public final ActivityScenarioRule<Activity> mActivityRule = new ActivityScenarioRule<>( + Activity.class); + + private Instrumentation mInstrumentation; + private Activity mActivity; + + @Before + public void setup() { + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mActivityRule.getScenario().onActivity(activity -> { + mActivity = activity; + }); + } + + @RequiresFlagsDisabled(Flags.FLAG_SURFACE_TRUSTED_OVERLAY) + @Test + public void setTrustedOverlayInputWindow() throws InterruptedException { + testTrustedOverlayChildHelper(false); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_SURFACE_TRUSTED_OVERLAY) + public void setTrustedOverlayChildLayer() throws InterruptedException { + testTrustedOverlayChildHelper(true); + } + + /** + * b/300659960 where setting spy window and trusted overlay were not happening in the same + * transaction causing the system to crash. This ensures there are no synchronization issues + * setting both spy window and trusted overlay. + */ + @Test + public void setSpyWindowDoesntCrash() throws InterruptedException { + IBinder[] tokens = new IBinder[1]; + CountDownLatch hostTokenReady = new CountDownLatch(1); + mInstrumentation.runOnMainSync(() -> { + WindowManager.LayoutParams params = mActivity.getWindow().getAttributes(); + params.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_SPY; + params.privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY; + mActivity.getWindow().setAttributes(params); + + View rootView = mActivity.getWindow().getDecorView(); + if (rootView.isAttachedToWindow()) { + tokens[0] = rootView.getWindowToken(); + hostTokenReady.countDown(); + } else { + rootView.getViewTreeObserver().addOnWindowAttachListener( + new ViewTreeObserver.OnWindowAttachListener() { + @Override + public void onWindowAttached() { + tokens[0] = rootView.getWindowToken(); + hostTokenReady.countDown(); + } + + @Override + public void onWindowDetached() { + } + }); + } + }); + + assertTrue("Failed to wait for host to get added", + hostTokenReady.await(TIMEOUT_S, TimeUnit.SECONDS)); + + boolean[] foundTrusted = new boolean[1]; + CtsWindowInfoUtils.waitForWindowInfos( + windowInfos -> { + for (var windowInfo : windowInfos) { + if (windowInfo.windowToken == tokens[0] && windowInfo.isTrustedOverlay) { + foundTrusted[0] = true; + return true; + } + } + return false; + }, TIMEOUT_S, TimeUnit.SECONDS); + + if (!foundTrusted[0]) { + CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, mName.getMethodName()); + } + + assertTrue("Failed to find window or was not marked trusted", foundTrusted[0]); + } + + private void testTrustedOverlayChildHelper(boolean expectedTrustedChild) + throws InterruptedException { + IBinder[] tokens = new IBinder[2]; + CountDownLatch hostTokenReady = new CountDownLatch(1); + mInstrumentation.runOnMainSync(() -> { + mActivity.getWindow().addPrivateFlags(PRIVATE_FLAG_TRUSTED_OVERLAY); + View rootView = mActivity.getWindow().getDecorView(); + if (rootView.isAttachedToWindow()) { + tokens[0] = rootView.getWindowToken(); + hostTokenReady.countDown(); + } else { + rootView.getViewTreeObserver().addOnWindowAttachListener( + new ViewTreeObserver.OnWindowAttachListener() { + @Override + public void onWindowAttached() { + tokens[0] = rootView.getWindowToken(); + hostTokenReady.countDown(); + } + + @Override + public void onWindowDetached() { + } + }); + } + }); + + assertTrue("Failed to wait for host to get added", + hostTokenReady.await(TIMEOUT_S, TimeUnit.SECONDS)); + + mInstrumentation.runOnMainSync(() -> { + WindowManager wm = mActivity.getSystemService(WindowManager.class); + + View childView = new View(mActivity) { + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + tokens[1] = getWindowToken(); + } + }; + WindowManager.LayoutParams params = new WindowManager.LayoutParams(); + params.token = tokens[0]; + params.type = TYPE_APPLICATION_PANEL; + wm.addView(childView, params); + }); + + boolean[] foundTrusted = new boolean[2]; + + CtsWindowInfoUtils.waitForWindowInfos( + windowInfos -> { + for (var windowInfo : windowInfos) { + if (windowInfo.windowToken == tokens[0] + && windowInfo.isTrustedOverlay) { + foundTrusted[0] = true; + } else if (windowInfo.windowToken == tokens[1] + && windowInfo.isTrustedOverlay) { + foundTrusted[1] = true; + } + } + return foundTrusted[0] && foundTrusted[1]; + }, TIMEOUT_S, TimeUnit.SECONDS); + + if (!foundTrusted[0] || !foundTrusted[1]) { + CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, mName.getMethodName()); + } + + assertTrue("Failed to find parent window or was not marked trusted", foundTrusted[0]); + assertEquals("Failed to find child window or was not marked trusted", expectedTrustedChild, + foundTrusted[1]); + } +} diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 6cebe0af7a35..f3bf026ddc6e 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -106,6 +106,7 @@ import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.IoThread; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener; @@ -201,7 +202,8 @@ public class UsageStatsService extends SystemService implements static final int MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED = 9; private final Object mLock = new Object(); - Handler mHandler; + private Handler mHandler; + private Handler mIoHandler; AppOpsManager mAppOps; UserManager mUserManager; PackageManager mPackageManager; @@ -233,7 +235,7 @@ public class UsageStatsService extends SystemService implements private final SparseArray<LinkedList<Event>> mReportedEvents = new SparseArray<>(); final SparseArray<ArraySet<String>> mUsageReporters = new SparseArray(); final SparseArray<ActivityData> mVisibleActivities = new SparseArray(); - @GuardedBy("mLock") + @GuardedBy("mLaunchTimeAlarmQueues") // Don't hold the main lock private final SparseArray<LaunchTimeAlarmQueue> mLaunchTimeAlarmQueues = new SparseArray<>(); @GuardedBy("mUsageEventListeners") // Don't hold the main lock when calling out private final ArraySet<UsageStatsManagerInternal.UsageEventListener> mUsageEventListeners = @@ -279,6 +281,38 @@ public class UsageStatsService extends SystemService implements } } + private final Handler.Callback mIoHandlerCallback = (msg) -> { + switch (msg.what) { + case MSG_UID_STATE_CHANGED: { + final int uid = msg.arg1; + final int procState = msg.arg2; + + final int newCounter = (procState <= ActivityManager.PROCESS_STATE_TOP) ? 0 : 1; + synchronized (mUidToKernelCounter) { + final int oldCounter = mUidToKernelCounter.get(uid, 0); + if (newCounter != oldCounter) { + mUidToKernelCounter.put(uid, newCounter); + try { + FileUtils.stringToFile(KERNEL_COUNTER_FILE, uid + " " + newCounter); + } catch (IOException e) { + Slog.w(TAG, "Failed to update counter set: " + e); + } + } + } + return true; + } + case MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK: { + final int userId = msg.arg1; + Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, + "usageStatsHandleEstimatedLaunchTimesOnUser(" + userId + ")"); + handleEstimatedLaunchTimesOnUserUnlock(userId); + Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + return true; + } + } + return false; + }; + private final Injector mInjector; public UsageStatsService(Context context) { @@ -299,6 +333,7 @@ public class UsageStatsService extends SystemService implements mPackageManager = getContext().getPackageManager(); mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mHandler = new H(BackgroundThread.get().getLooper()); + mIoHandler = new Handler(IoThread.get().getLooper(), mIoHandlerCallback); mAppStandby = mInjector.getAppStandbyController(getContext()); mResponseStatsTracker = new BroadcastResponseStatsTracker(mAppStandby, getContext()); @@ -424,6 +459,9 @@ public class UsageStatsService extends SystemService implements } mUserUnlockedStates.remove(userId); mUserState.put(userId, null); // release the service (mainly for GC) + } + + synchronized (mLaunchTimeAlarmQueues) { LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId); if (alarmQueue != null) { alarmQueue.removeAllAlarms(); @@ -479,10 +517,12 @@ public class UsageStatsService extends SystemService implements } reportEvent(unlockEvent, userId); - mHandler.obtainMessage(MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK, userId, 0).sendToTarget(); + mIoHandler.obtainMessage(MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK, + userId, 0).sendToTarget(); // Remove all the stats stored in system DE. deleteRecursively(new File(Environment.getDataSystemDeDirectory(userId), "usagestats")); + // Force a flush to disk for the current user to ensure important events are persisted. // Note: there is a very very small chance that the system crashes between deleting // the stats above from DE and persisting them to CE here in which case we will lose @@ -601,7 +641,7 @@ public class UsageStatsService extends SystemService implements private final IUidObserver mUidObserver = new UidObserver() { @Override public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) { - mHandler.obtainMessage(MSG_UID_STATE_CHANGED, uid, procState).sendToTarget(); + mIoHandler.obtainMessage(MSG_UID_STATE_CHANGED, uid, procState).sendToTarget(); } @Override @@ -673,16 +713,18 @@ public class UsageStatsService extends SystemService implements callingPid, callingUid) == PackageManager.PERMISSION_GRANTED); } - private static void deleteRecursively(File f) { - File[] files = f.listFiles(); - if (files != null) { - for (File subFile : files) { - deleteRecursively(subFile); + private static void deleteRecursively(final File path) { + if (path.isDirectory()) { + final File[] files = path.listFiles(); + if (files != null) { + for (File subFile : files) { + deleteRecursively(subFile); + } } } - if (f.exists() && !f.delete()) { - Slog.e(TAG, "Failed to delete " + f); + if (path.exists() && !path.delete()) { + Slog.e(TAG, "Failed to delete " + path); } } @@ -1244,6 +1286,9 @@ public class UsageStatsService extends SystemService implements Slog.i(TAG, "Removing user " + userId + " and all data."); mUserState.remove(userId); mAppTimeLimit.onUserRemoved(userId); + } + + synchronized (mLaunchTimeAlarmQueues) { final LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId); if (alarmQueue != null) { alarmQueue.removeAllAlarms(); @@ -1274,6 +1319,13 @@ public class UsageStatsService extends SystemService implements } } + synchronized (mLaunchTimeAlarmQueues) { + final LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId); + if (alarmQueue != null) { + alarmQueue.removeAlarmForKey(packageName); + } + } + final int tokenRemoved; synchronized (mLock) { final long timeRemoved = System.currentTimeMillis(); @@ -1282,10 +1334,7 @@ public class UsageStatsService extends SystemService implements // when the user service is initialized and package manager is queried. return; } - final LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId); - if (alarmQueue != null) { - alarmQueue.removeAlarmForKey(packageName); - } + final UserUsageStatsService userService = mUserState.get(userId); if (userService == null) { return; @@ -1495,60 +1544,63 @@ public class UsageStatsService extends SystemService implements estimatedLaunchTime = calculateEstimatedPackageLaunchTime(userId, packageName); mAppStandby.setEstimatedLaunchTime(packageName, userId, estimatedLaunchTime); - synchronized (mLock) { - LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId); - if (alarmQueue == null) { - alarmQueue = new LaunchTimeAlarmQueue( - userId, getContext(), BackgroundThread.get().getLooper()); - mLaunchTimeAlarmQueues.put(userId, alarmQueue); - } - alarmQueue.addAlarm(packageName, - SystemClock.elapsedRealtime() + (estimatedLaunchTime - now)); - } + getOrCreateLaunchTimeAlarmQueue(userId).addAlarm(packageName, + SystemClock.elapsedRealtime() + (estimatedLaunchTime - now)); } return estimatedLaunchTime; } + private LaunchTimeAlarmQueue getOrCreateLaunchTimeAlarmQueue(int userId) { + synchronized (mLaunchTimeAlarmQueues) { + LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId); + if (alarmQueue == null) { + alarmQueue = new LaunchTimeAlarmQueue( + userId, getContext(), BackgroundThread.get().getLooper()); + mLaunchTimeAlarmQueues.put(userId, alarmQueue); + } + + return alarmQueue; + } + } + @CurrentTimeMillisLong private long calculateEstimatedPackageLaunchTime(int userId, String packageName) { - synchronized (mLock) { - final long endTime = System.currentTimeMillis(); - final long beginTime = endTime - ONE_WEEK; - final long unknownTime = endTime + UNKNOWN_LAUNCH_TIME_DELAY_MS; - final UsageEvents events = queryEarliestEventsForPackage( - userId, beginTime, endTime, packageName, Event.ACTIVITY_RESUMED); - if (events == null) { - if (DEBUG) { - Slog.d(TAG, "No events for " + userId + ":" + packageName); - } - return unknownTime; + final long endTime = System.currentTimeMillis(); + final long beginTime = endTime - ONE_WEEK; + final long unknownTime = endTime + UNKNOWN_LAUNCH_TIME_DELAY_MS; + final UsageEvents events = queryEarliestEventsForPackage( + userId, beginTime, endTime, packageName, Event.ACTIVITY_RESUMED); + if (events == null) { + if (DEBUG) { + Slog.d(TAG, "No events for " + userId + ":" + packageName); + } + return unknownTime; + } + final UsageEvents.Event event = new UsageEvents.Event(); + final boolean hasMoreThan24HoursOfHistory; + if (events.getNextEvent(event)) { + hasMoreThan24HoursOfHistory = endTime - event.getTimeStamp() > ONE_DAY; + if (DEBUG) { + Slog.d(TAG, userId + ":" + packageName + " history > 24 hours=" + + hasMoreThan24HoursOfHistory); + } + } else { + if (DEBUG) { + Slog.d(TAG, userId + ":" + packageName + " has no events"); } - final UsageEvents.Event event = new UsageEvents.Event(); - final boolean hasMoreThan24HoursOfHistory; - if (events.getNextEvent(event)) { - hasMoreThan24HoursOfHistory = endTime - event.getTimeStamp() > ONE_DAY; - if (DEBUG) { - Slog.d(TAG, userId + ":" + packageName + " history > 24 hours=" - + hasMoreThan24HoursOfHistory); - } - } else { - if (DEBUG) { - Slog.d(TAG, userId + ":" + packageName + " has no events"); - } - return unknownTime; - } - do { - if (event.getEventType() == Event.ACTIVITY_RESUMED) { - final long timestamp = event.getTimeStamp(); - final long nextLaunch = - calculateNextLaunchTime(hasMoreThan24HoursOfHistory, timestamp); - if (nextLaunch > endTime) { - return nextLaunch; - } - } - } while (events.getNextEvent(event)); return unknownTime; } + do { + if (event.getEventType() == Event.ACTIVITY_RESUMED) { + final long timestamp = event.getTimeStamp(); + final long nextLaunch = + calculateNextLaunchTime(hasMoreThan24HoursOfHistory, timestamp); + if (nextLaunch > endTime) { + return nextLaunch; + } + } + } while (events.getNextEvent(event)); + return unknownTime; } @CurrentTimeMillisLong @@ -1569,61 +1621,54 @@ public class UsageStatsService extends SystemService implements } private void handleEstimatedLaunchTimesOnUserUnlock(int userId) { - synchronized (mLock) { - final long nowElapsed = SystemClock.elapsedRealtime(); - final long now = System.currentTimeMillis(); - final long beginTime = now - ONE_WEEK; - final UsageEvents events = queryEarliestAppEvents( - userId, beginTime, now, Event.ACTIVITY_RESUMED); - if (events == null) { - return; - } - final ArrayMap<String, Boolean> hasMoreThan24HoursOfHistory = new ArrayMap<>(); - final UsageEvents.Event event = new UsageEvents.Event(); - LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId); - if (alarmQueue == null) { - alarmQueue = new LaunchTimeAlarmQueue( - userId, getContext(), BackgroundThread.get().getLooper()); - mLaunchTimeAlarmQueues.put(userId, alarmQueue); - } - boolean changedTimes = false; - for (boolean unprocessedEvent = events.getNextEvent(event); unprocessedEvent; - unprocessedEvent = events.getNextEvent(event)) { - final String packageName = event.getPackageName(); - if (!hasMoreThan24HoursOfHistory.containsKey(packageName)) { - boolean hasHistory = now - event.getTimeStamp() > ONE_DAY; - if (DEBUG) { - Slog.d(TAG, - userId + ":" + packageName + " history > 24 hours=" + hasHistory); - } - hasMoreThan24HoursOfHistory.put(packageName, hasHistory); + final long nowElapsed = SystemClock.elapsedRealtime(); + final long now = System.currentTimeMillis(); + final long beginTime = now - ONE_WEEK; + final UsageEvents events = queryEarliestAppEvents( + userId, beginTime, now, Event.ACTIVITY_RESUMED); + if (events == null) { + return; + } + final ArrayMap<String, Boolean> hasMoreThan24HoursOfHistory = new ArrayMap<>(); + final UsageEvents.Event event = new UsageEvents.Event(); + boolean changedTimes = false; + final LaunchTimeAlarmQueue alarmQueue = getOrCreateLaunchTimeAlarmQueue(userId); + for (boolean unprocessedEvent = events.getNextEvent(event); unprocessedEvent; + unprocessedEvent = events.getNextEvent(event)) { + final String packageName = event.getPackageName(); + if (!hasMoreThan24HoursOfHistory.containsKey(packageName)) { + boolean hasHistory = now - event.getTimeStamp() > ONE_DAY; + if (DEBUG) { + Slog.d(TAG, + userId + ":" + packageName + " history > 24 hours=" + hasHistory); } - if (event.getEventType() == Event.ACTIVITY_RESUMED) { - long estimatedLaunchTime = - mAppStandby.getEstimatedLaunchTime(packageName, userId); - if (estimatedLaunchTime < now || estimatedLaunchTime == Long.MAX_VALUE) { - //noinspection ConstantConditions - estimatedLaunchTime = calculateNextLaunchTime( - hasMoreThan24HoursOfHistory.get(packageName), event.getTimeStamp()); - mAppStandby.setEstimatedLaunchTime( - packageName, userId, estimatedLaunchTime); - } - if (estimatedLaunchTime < now + ONE_WEEK) { - // Before a user is unlocked, we don't know when the app will be launched, - // so we give callers the UNKNOWN time. Now that we have a better estimate, - // we should notify them of the change. - if (DEBUG) { - Slog.d(TAG, "User " + userId + " unlock resulting in" - + " estimated launch time change for " + packageName); - } - changedTimes |= stageChangedEstimatedLaunchTime(userId, packageName); + hasMoreThan24HoursOfHistory.put(packageName, hasHistory); + } + if (event.getEventType() == Event.ACTIVITY_RESUMED) { + long estimatedLaunchTime = + mAppStandby.getEstimatedLaunchTime(packageName, userId); + if (estimatedLaunchTime < now || estimatedLaunchTime == Long.MAX_VALUE) { + //noinspection ConstantConditions + estimatedLaunchTime = calculateNextLaunchTime( + hasMoreThan24HoursOfHistory.get(packageName), event.getTimeStamp()); + mAppStandby.setEstimatedLaunchTime( + packageName, userId, estimatedLaunchTime); + } + if (estimatedLaunchTime < now + ONE_WEEK) { + // Before a user is unlocked, we don't know when the app will be launched, + // so we give callers the UNKNOWN time. Now that we have a better estimate, + // we should notify them of the change. + if (DEBUG) { + Slog.d(TAG, "User " + userId + " unlock resulting in" + + " estimated launch time change for " + packageName); } - alarmQueue.addAlarm(packageName, nowElapsed + (estimatedLaunchTime - now)); + changedTimes |= stageChangedEstimatedLaunchTime(userId, packageName); } + alarmQueue.addAlarm(packageName, nowElapsed + (estimatedLaunchTime - now)); } - if (changedTimes) { - mHandler.sendEmptyMessage(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED); - } + } + if (changedTimes) { + mHandler.sendEmptyMessage(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED); } } @@ -1995,37 +2040,11 @@ public class UsageStatsService extends SystemService implements case MSG_PACKAGE_REMOVED: onPackageRemoved(msg.arg1, (String) msg.obj); break; - case MSG_UID_STATE_CHANGED: { - final int uid = msg.arg1; - final int procState = msg.arg2; - - final int newCounter = (procState <= ActivityManager.PROCESS_STATE_TOP) ? 0 : 1; - synchronized (mUidToKernelCounter) { - final int oldCounter = mUidToKernelCounter.get(uid, 0); - if (newCounter != oldCounter) { - mUidToKernelCounter.put(uid, newCounter); - try { - FileUtils.stringToFile(KERNEL_COUNTER_FILE, uid + " " + newCounter); - } catch (IOException e) { - Slog.w(TAG, "Failed to update counter set: " + e); - } - } - } - break; - } case MSG_ON_START: synchronized (mLock) { loadGlobalComponentUsageLocked(); } break; - case MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK: { - final int userId = msg.arg1; - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, - "usageStatsHandleEstimatedLaunchTimesOnUser(" + userId + ")"); - handleEstimatedLaunchTimesOnUserUnlock(userId); - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); - } - break; case MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED: { removeMessages(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED); diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 7d9b3790c1b5..a7675d694a24 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -1894,7 +1894,7 @@ public final class Call { * Tones are both played locally for the user to hear and sent to the network to be relayed * to the remote device. * <p> - * You must ensure that any call to {@link #playDtmfTone(char}) is followed by a matching + * You must ensure that any call to {@link #playDtmfTone(char)} is followed by a matching * call to {@link #stopDtmfTone()} and that each tone is stopped before a new one is started. * The play and stop commands are relayed to the underlying * {@link android.telecom.ConnectionService} as executed; implementations may not correctly diff --git a/telecomm/java/android/telecom/CallControl.java b/telecomm/java/android/telecom/CallControl.java index 50f2ad4561cc..24d39182add6 100644 --- a/telecomm/java/android/telecom/CallControl.java +++ b/telecomm/java/android/telecom/CallControl.java @@ -225,7 +225,7 @@ public final class CallControl { /** * Request start a call streaming session. On receiving valid request, telecom will bind to - * the {@link CallStreamingService} implemented by a general call streaming sender. So that the + * the {@code CallStreamingService} implemented by a general call streaming sender. So that the * call streaming sender can perform streaming local device audio to another remote device and * control the call during streaming. * diff --git a/telecomm/java/android/telecom/CallControlCallback.java b/telecomm/java/android/telecom/CallControlCallback.java index eac2e64aa2ab..0166022abeb8 100644 --- a/telecomm/java/android/telecom/CallControlCallback.java +++ b/telecomm/java/android/telecom/CallControlCallback.java @@ -69,7 +69,7 @@ public interface CallControlCallback { /** * Telecom is informing the client to answer an incoming call and set it to active. * - * @param videoState see {@link android.telecom.CallAttributes.CallType} for valid states + * @param videoState the video state * @param wasCompleted The {@link Consumer} to be completed. If the client can answer the call * on their end, {@link Consumer#accept(Object)} should be called with * {@link Boolean#TRUE}. diff --git a/telecomm/java/android/telecom/PhoneAccountSuggestion.java b/telecomm/java/android/telecom/PhoneAccountSuggestion.java index d9f89d544f40..c83804fde8fe 100644 --- a/telecomm/java/android/telecom/PhoneAccountSuggestion.java +++ b/telecomm/java/android/telecom/PhoneAccountSuggestion.java @@ -68,7 +68,7 @@ public final class PhoneAccountSuggestion implements Parcelable { /** * Creates a new instance of {@link PhoneAccountSuggestion}. This constructor is intended for - * use by apps implementing a {@link PhoneAccountSuggestionService}, and generally should not be + * use by apps implementing a {@code PhoneAccountSuggestionService}, and generally should not be * used by dialer apps other than for testing purposes. * * @param handle The {@link PhoneAccountHandle} for this suggestion. diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 98bbb40282c9..63e91ad414de 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -5073,7 +5073,6 @@ public class CarrierConfigManager { * MMTEL and RCS. * <p> * The default value for this configuration is {@code false}. - * @see android.telephony.ims.SipDelegateManager */ public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL = KEY_PREFIX + "ims_single_registration_required_bool"; @@ -5648,8 +5647,8 @@ public class CarrierConfigManager { * <li>{@link #KEY_CAPABILITY_TYPE_SMS_INT_ARRAY}</li> * <li>{@link #KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY}</li> * </ul> - * <p> The values are defined in - * {@link ImsRegistrationImplBase.ImsRegistrationTech} + * <p> The values are defined as {@code REGISTRATION_TECH_*} constants in + * {@link android.telephony.ims.stub.ImsRegistrationImplBase}. * * changing mmtel_requires_provisioning_bundle requires changes to * carrier_volte_provisioning_required_bool and vice versa @@ -5661,12 +5660,12 @@ public class CarrierConfigManager { /** * List of different RAT technologies on which Provisioning for Voice calling (IR.92) * is supported. - * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE * <p>Possible values are, - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR} + * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE */ public static final String KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY = KEY_PREFIX + "capability_type_voice_int_array"; @@ -5674,12 +5673,12 @@ public class CarrierConfigManager { /** * List of different RAT technologies on which Provisioning for Video Telephony (IR.94) * is supported. - * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO * <p>Possible values are, - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR} + * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO */ public static final String KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY = KEY_PREFIX + "capability_type_video_int_array"; @@ -5687,24 +5686,24 @@ public class CarrierConfigManager { /** * List of different RAT technologies on which Provisioning for XCAP over Ut for * supplementary services. (IR.92) is supported. - * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT * <p>Possible values are, - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR} + * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT */ public static final String KEY_CAPABILITY_TYPE_UT_INT_ARRAY = KEY_PREFIX + "capability_type_ut_int_array"; /** * List of different RAT technologies on which Provisioning for SMS (IR.92) is supported. - * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS * <p>Possible values are, - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR} + * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS */ public static final String KEY_CAPABILITY_TYPE_SMS_INT_ARRAY = KEY_PREFIX + "capability_type_sms_int_array"; @@ -5712,12 +5711,12 @@ public class CarrierConfigManager { /** * List of different RAT technologies on which Provisioning for Call Composer * (section 2.4 of RCC.20) is supported. - * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_CALL_COMPOSER * <p>Possible values are, - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR} + * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_CALL_COMPOSER */ public static final String KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY = KEY_PREFIX + "capability_type_call_composer_int_array"; @@ -5732,8 +5731,8 @@ public class CarrierConfigManager { * <li>{@link #KEY_CAPABILITY_TYPE_OPTIONS_UCE_INT_ARRAY}</li> * <li>{@link #KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY}</li> * </ul> - * <p> The values are defined in - * {@link ImsRegistrationImplBase.ImsRegistrationTech} + * <p> The values are defined as {@code REGISTRATION_TECH_*} constants in + * {@link android.telephony.ims.stub.ImsRegistrationImplBase}. */ public static final String KEY_RCS_REQUIRES_PROVISIONING_BUNDLE = KEY_PREFIX + "rcs_requires_provisioning_bundle"; @@ -5742,12 +5741,11 @@ public class CarrierConfigManager { * This carrier supports User Capability Exchange using SIP OPTIONS as defined by the * framework. If set, the RcsFeature should support capability exchange using SIP OPTIONS. * If not set, this RcsFeature should not service capability requests. - * @see RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE * <p>Possible values are, - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR} */ public static final String KEY_CAPABILITY_TYPE_OPTIONS_UCE_INT_ARRAY = KEY_PREFIX + "capability_type_options_uce_int_array"; @@ -5757,12 +5755,11 @@ public class CarrierConfigManager { * framework. If set, the RcsFeature should support capability exchange using a presence * server. If not set, this RcsFeature should not publish capabilities or service capability * requests using presence. - * @see RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE * <p>Possible values are, - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR} */ public static final String KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY = KEY_PREFIX + "capability_type_presence_uce_int_array"; @@ -9640,7 +9637,7 @@ public class CarrierConfigManager { /** * A list of premium capabilities the carrier supports. Applications can prompt users to * purchase these premium capabilities from their carrier for a performance boost. - * Valid values are any of {@link TelephonyManager.PremiumCapability}. + * Valid values are any of {@link TelephonyManager}'s {@code PREMIUM_CAPABILITY_*} constants. * * This is empty by default, indicating that no premium capabilities are supported. * diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java index 631013fc485e..cb4a6e7479cf 100644 --- a/telephony/java/android/telephony/NetworkRegistrationInfo.java +++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java @@ -625,7 +625,7 @@ public final class NetworkRegistrationInfo implements Parcelable { } /** - * @return The access network technology {@link NetworkType}. + * @return The access network technology network type.. */ public @NetworkType int getAccessNetworkTechnology() { return mAccessNetworkTechnology; diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index fa5fd875a024..8e90fe7ea975 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -1364,7 +1364,7 @@ public class SubscriptionManager { public static class OnSubscriptionsChangedListener { /** - * After {@link Build.VERSION_CODES.Q}, it is no longer necessary to instantiate a + * After {@link Build.VERSION_CODES#Q}, it is no longer necessary to instantiate a * Handler inside of the OnSubscriptionsChangedListener in all cases, so it will only * be done for callers that do not supply an Executor. */ @@ -1388,13 +1388,14 @@ public class SubscriptionManager { /** * Create an OnSubscriptionsChangedListener. * - * For callers targeting {@link Build.VERSION_CODES.P} or earlier, this can only be called + * For callers targeting {@link Build.VERSION_CODES#P} or earlier, this can only be called * on a thread that already has a prepared Looper. Callers targeting Q or later should * subsequently use {@link SubscriptionManager#addOnSubscriptionsChangedListener( * Executor, OnSubscriptionsChangedListener)}. * - * On OS versions prior to {@link Build.VERSION_CODES.V} callers should assume that this - * call will fail if invoked on a thread that does not already have a prepared looper. + * On OS versions prior to {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} callers should + * assume that this call will fail if invoked on a thread that does not already have a + * prepared looper. */ public OnSubscriptionsChangedListener() { mCreatorLooper = Looper.myLooper(); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 234ca918a144..548fa97db599 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -13132,8 +13132,8 @@ public class TelephonyManager { * </ul> * * @param executor The executor on which the result listener will be called. - * @param resultListener {@link Consumer} that will be called with the result fetched - * from the radio of type {@link CarrierRestrictionStatus} + * @param resultListener {@link Consumer} that will be called with the carrier restriction + * status result fetched from the radio * @throws SecurityException if the caller does not have the required permission/privileges or * if the caller is not pre-registered. */ @@ -13465,7 +13465,7 @@ public class TelephonyManager { public static final int DATA_ENABLED_REASON_THERMAL = 3; /** - * To indicate data was enabled or disabled due to {@link MobileDataPolicy} overrides. + * To indicate data was enabled or disabled due to mobile data policy overrides. * Note that this is not a valid reason for {@link #setDataEnabledForReason(int, boolean)} and * is only used to indicate that data enabled was changed due to an override. */ @@ -14571,7 +14571,7 @@ public class TelephonyManager { * @param needValidation whether validation is needed before switch happens. * @param executor The executor of where the callback will execute. * @param callback Callback will be triggered once it succeeds or failed. - * See {@link TelephonyManager.SetOpportunisticSubscriptionResult} + * See the {@code SET_OPPORTUNISTIC_SUB_*} constants * for more details. Pass null if don't care about the result. */ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) @@ -17516,7 +17516,7 @@ public class TelephonyManager { public @interface PurchasePremiumCapabilityResult {} /** - * Returns the purchase result {@link PurchasePremiumCapabilityResult} as a String. + * Returns the purchase result as a String. * * @param result The purchase premium capability result. * @return The purchase result as a String. @@ -17570,7 +17570,6 @@ public class TelephonyManager { * @param capability The premium capability to purchase. * @param executor The callback executor for the response. * @param callback The result of the purchase request. - * One of {@link PurchasePremiumCapabilityResult}. * @throws SecurityException if the caller does not hold permissions * READ_BASIC_PHONE_STATE or INTERNET. * @see #isPremiumCapabilityAvailableForPurchase(int) to check whether the capability is valid. diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 26c17a461cf2..e9af486219f7 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -532,7 +532,7 @@ public class ApnSetting implements Parcelable { /** * Returns the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought * up by this APN setting. Note this value will only be used when MTU size is not provided - * in {@link DataCallResponse#getMtuV4()} during network bring up. + * in {@code DataCallResponse#getMtuV4()} during network bring up. * * @return the MTU size in bytes of the route. */ @@ -542,7 +542,7 @@ public class ApnSetting implements Parcelable { /** * Returns the MTU size of the IPv6 mobile interface to which the APN connected. Note this value - * will only be used when MTU size is not provided in {@link DataCallResponse#getMtuV6()} + * will only be used when MTU size is not provided in {@code DataCallResponse#getMtuV6()} * during network bring up. * * @return the MTU size in bytes of the route. @@ -1787,7 +1787,7 @@ public class ApnSetting implements Parcelable { /** * Set the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought * up by this APN setting. Note this value will only be used when MTU size is not provided - * in {@link DataCallResponse#getMtuV4()} during network bring up. + * in {@code DataCallResponse#getMtuV4()} during network bring up. * * @param mtuV4 the MTU size in bytes of the route. */ @@ -1799,7 +1799,7 @@ public class ApnSetting implements Parcelable { /** * Set the default MTU (Maximum Transmission Unit) size in bytes of the IPv6 routes brought * up by this APN setting. Note this value will only be used when MTU size is not provided - * in {@link DataCallResponse#getMtuV6()} during network bring up. + * in {@code DataCallResponse#getMtuV6()} during network bring up. * * @param mtuV6 the MTU size in bytes of the route. */ diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index ed4627631dd5..b9a7d439114a 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -249,7 +249,7 @@ public class EuiccManager { * * <p>{@link #EXTRA_USE_QR_SCANNER} not set or set to false: The LPA should try to get an * activation code from the carrier app by binding to the carrier app service implementing - * {@link android.service.euicc.EuiccService#ACTION_BIND_CARRIER_PROVISIONING_SERVICE}. + * {@code android.service.euicc.EuiccService#ACTION_BIND_CARRIER_PROVISIONING_SERVICE}. * <p>{@link #EXTRA_USE_QR_SCANNER} set to true: The LPA should launch a QR scanner for the user * to scan an eSIM profile QR code. * diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index caee4e2ca277..2172d7de0dd7 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -561,7 +561,7 @@ public class ImsMmTelManager implements RegistrationManager { * @param c The MmTel {@link CapabilityCallback} to be registered. * @see #unregisterMmTelCapabilityCallback(CapabilityCallback) * @throws ImsException if the subscription associated with this callback is valid, but - * the {@link ImsService} associated with the subscription is not available. This can happen if + * the {@code ImsService} associated with the subscription is not available. This can happen if * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed * reason. */ diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java index 4439e5c35d83..2b49bcd4e928 100644 --- a/telephony/java/android/telephony/ims/ImsRcsManager.java +++ b/telephony/java/android/telephony/ims/ImsRcsManager.java @@ -247,7 +247,7 @@ public class ImsRcsManager { * @param c The {@link RegistrationManager.RegistrationCallback} to be added. * @see #unregisterImsRegistrationCallback(RegistrationManager.RegistrationCallback) * @throws ImsException if the subscription associated with this callback is valid, but - * the {@link ImsService} associated with the subscription is not available. This can happen if + * the {@code ImsService} associated with the subscription is not available. This can happen if * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed * reason. */ diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java index 37a6a7ebf953..1c5d1e940030 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -1469,9 +1469,8 @@ public class ProvisioningManager { /** * Get the provisioning status for the IMS MmTel capability specified. * - * If provisioning is not required for the queried - * {@link MmTelFeature.MmTelCapabilities.MmTelCapability} and - * {@link ImsRegistrationImplBase.ImsRegistrationTech} combination specified, this method will + * If provisioning is not required for the queried {@code capability} and + * {@code tech} combination specified, this method will * always return {@code true}. * * <p> Requires Permission: @@ -1503,7 +1502,7 @@ public class ProvisioningManager { * Get the provisioning status for the IMS RCS capability specified. * * If provisioning is not required for the queried - * {@link ImsRcsManager.RcsImsCapabilityFlag} or if the device does not support IMS + * {@code capability} or if the device does not support IMS * this method will always return {@code true}. * * @see CarrierConfigManager.Ims#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL @@ -1533,7 +1532,7 @@ public class ProvisioningManager { * Get the provisioning status for the IMS RCS capability specified. * * If provisioning is not required for the queried - * {@link ImsRcsManager.RcsImsCapabilityFlag} or if the device does not support IMS + * {@code capability} or if the device does not support IMS * this method will always return {@code true}. * * <p> Requires Permission: diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java index 873ce6064cca..b528866371cb 100644 --- a/telephony/java/android/telephony/ims/RegistrationManager.java +++ b/telephony/java/android/telephony/ims/RegistrationManager.java @@ -31,7 +31,6 @@ import android.os.Bundle; import android.telephony.AccessNetworkConstants; import android.telephony.NetworkRegistrationInfo; import android.telephony.ims.aidl.IImsRegistrationCallback; -import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.Log; @@ -42,7 +41,7 @@ import java.util.concurrent.Executor; import java.util.function.Consumer; /** - * Manages IMS Service registration state for associated {@link ImsFeature}s. + * Manages IMS Service registration state for associated {@code ImsFeature}s. */ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS) public interface RegistrationManager { @@ -394,7 +393,7 @@ public interface RegistrationManager { * @param c The {@link RegistrationCallback} to be added. * @see #unregisterImsRegistrationCallback(RegistrationCallback) * @throws ImsException if the subscription associated with this callback is valid, but - * the {@link ImsService} associated with the subscription is not available. This can happen if + * the {@code ImsService} associated with the subscription is not available. This can happen if * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed * reason. */ diff --git a/tests/BatteryStatsPerfTest/Android.bp b/tests/BatteryStatsPerfTest/Android.bp index 5233a5b8654e..c2a70151fa13 100644 --- a/tests/BatteryStatsPerfTest/Android.bp +++ b/tests/BatteryStatsPerfTest/Android.bp @@ -27,7 +27,7 @@ android_test { static_libs: [ "androidx.test.rules", "apct-perftests-utils", - "truth-prebuilt", + "truth", ], platform_apis: true, certificate: "platform", diff --git a/tests/BinaryTransparencyHostTest/Android.bp b/tests/BinaryTransparencyHostTest/Android.bp index 615990f22e3c..38cb9869f165 100644 --- a/tests/BinaryTransparencyHostTest/Android.bp +++ b/tests/BinaryTransparencyHostTest/Android.bp @@ -30,7 +30,7 @@ java_test_host { "compatibility-host-util", ], static_libs: [ - "truth-prebuilt", + "truth", ], data: [ ":BinaryTransparencyTestApp", diff --git a/tests/BlobStoreTestUtils/Android.bp b/tests/BlobStoreTestUtils/Android.bp index c4faf7f4fb11..1fb73e2c0967 100644 --- a/tests/BlobStoreTestUtils/Android.bp +++ b/tests/BlobStoreTestUtils/Android.bp @@ -22,12 +22,12 @@ package { } java_library { - name: "BlobStoreTestUtils", - srcs: ["src/**/*.java"], - static_libs: [ - "truth-prebuilt", - "androidx.test.uiautomator_uiautomator", - "androidx.test.ext.junit", - ], - sdk_version: "test_current", + name: "BlobStoreTestUtils", + srcs: ["src/**/*.java"], + static_libs: [ + "truth", + "androidx.test.uiautomator_uiautomator", + "androidx.test.ext.junit", + ], + sdk_version: "test_current", } diff --git a/tests/ChoreographerTests/Android.bp b/tests/ChoreographerTests/Android.bp index ca3026705c63..5d49120ee702 100644 --- a/tests/ChoreographerTests/Android.bp +++ b/tests/ChoreographerTests/Android.bp @@ -34,7 +34,7 @@ android_test { "androidx.test.rules", "compatibility-device-util-axt", "com.google.android.material_material", - "truth-prebuilt", + "truth", ], jni_libs: [ "libchoreographertests_jni", diff --git a/tests/CtsSurfaceControlTestsStaging/Android.bp b/tests/CtsSurfaceControlTestsStaging/Android.bp index 680952157fdc..96e4a9ea4300 100644 --- a/tests/CtsSurfaceControlTestsStaging/Android.bp +++ b/tests/CtsSurfaceControlTestsStaging/Android.bp @@ -37,7 +37,7 @@ android_test { "compatibility-device-util-axt", "com.google.android.material_material", "SurfaceFlingerProperties", - "truth-prebuilt", + "truth", ], resource_dirs: ["src/main/res"], certificate: "platform", diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.bp b/tests/DynamicCodeLoggerIntegrationTests/Android.bp index 448d46fe5e4e..3f2c80831565 100644 --- a/tests/DynamicCodeLoggerIntegrationTests/Android.bp +++ b/tests/DynamicCodeLoggerIntegrationTests/Android.bp @@ -47,7 +47,7 @@ android_test { static_libs: [ "androidx.test.rules", - "truth-prebuilt", + "truth", ], compile_multilib: "both", diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp index a2ae56eaeadc..82aa85d55e4c 100644 --- a/tests/FlickerTests/Android.bp +++ b/tests/FlickerTests/Android.bp @@ -236,7 +236,7 @@ java_library { static_libs: [ "flickerlib", "flickerlib-helpers", - "truth-prebuilt", + "truth", "app-helpers-core", ], } @@ -255,7 +255,7 @@ java_library { "flickerlib", "flickerlib-apphelpers", "flickerlib-helpers", - "truth-prebuilt", + "truth", "app-helpers-core", "wm-flicker-window-extensions", ], diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp index 365e00e2b652..cf2d5d69552f 100644 --- a/tests/Input/Android.bp +++ b/tests/Input/Android.bp @@ -9,6 +9,10 @@ package { android_test { name: "InputTests", + defaults: [ + // For ExtendedMockito dependencies. + "modules-utils-testable-device-config-defaults", + ], srcs: [ "src/**/*.java", "src/**/*.kt", @@ -35,7 +39,7 @@ android_test { "services.core.unboosted", "testables", "testng", - "truth-prebuilt", + "truth", ], libs: [ "android.test.mock", diff --git a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt index b64775103ab2..fa86e9c4ec0a 100644 --- a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt +++ b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt @@ -32,11 +32,16 @@ import android.os.Bundle import android.os.test.TestLooper import android.platform.test.annotations.Presubmit import android.provider.Settings +import android.util.proto.ProtoOutputStream import android.view.InputDevice import android.view.inputmethod.InputMethodInfo import android.view.inputmethod.InputMethodSubtype import androidx.test.core.R import androidx.test.core.app.ApplicationProvider +import com.android.dx.mockito.inline.extended.ExtendedMockito +import com.android.internal.os.KeyboardConfiguredProto +import com.android.internal.util.FrameworkStatsLog +import com.android.modules.utils.testing.ExtendedMockitoRule import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertNotEquals @@ -46,9 +51,9 @@ import org.junit.Assert.assertThrows import org.junit.Before import org.junit.Rule import org.junit.Test +import org.mockito.ArgumentMatchers import org.mockito.Mock import org.mockito.Mockito -import org.mockito.junit.MockitoJUnit import java.io.FileNotFoundException import java.io.FileOutputStream import java.io.IOException @@ -96,6 +101,9 @@ class KeyboardLayoutManagerTests { private const val ENGLISH_US_LAYOUT_NAME = "keyboard_layout_english_us" private const val ENGLISH_UK_LAYOUT_NAME = "keyboard_layout_english_uk" private const val VENDOR_SPECIFIC_LAYOUT_NAME = "keyboard_layout_vendorId:1,productId:1" + const val LAYOUT_TYPE_QWERTZ = 2 + const val LAYOUT_TYPE_QWERTY = 1 + const val LAYOUT_TYPE_DEFAULT = 0 } private val ENGLISH_US_LAYOUT_DESCRIPTOR = createLayoutDescriptor(ENGLISH_US_LAYOUT_NAME) @@ -103,8 +111,10 @@ class KeyboardLayoutManagerTests { private val VENDOR_SPECIFIC_LAYOUT_DESCRIPTOR = createLayoutDescriptor(VENDOR_SPECIFIC_LAYOUT_NAME) - @get:Rule - val rule = MockitoJUnit.rule()!! + @JvmField + @Rule + val extendedMockitoRule = ExtendedMockitoRule.Builder(this) + .mockStatic(FrameworkStatsLog::class.java).build()!! @Mock private lateinit var iInputManager: IInputManager @@ -145,7 +155,9 @@ class KeyboardLayoutManagerTests { override fun finishWrite(fos: FileOutputStream?, success: Boolean) {} }) testLooper = TestLooper() - keyboardLayoutManager = KeyboardLayoutManager(context, native, dataStore, testLooper.looper) + keyboardLayoutManager = Mockito.spy( + KeyboardLayoutManager(context, native, dataStore, testLooper.looper) + ) setupInputDevices() setupBroadcastReceiver() setupIme() @@ -827,6 +839,100 @@ class KeyboardLayoutManagerTests { } } + @Test + fun testConfigurationLogged_onInputDeviceAdded_VirtualKeyboardBasedSelection() { + val imeInfos = listOf( + KeyboardLayoutManager.ImeInfo(0, imeInfo, + createImeSubtypeForLanguageTagAndLayoutType("de-Latn", "qwertz"))) + Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping + NewSettingsApiFlag(true).use { + keyboardLayoutManager.onInputDeviceAdded(keyboardDevice.id) + ExtendedMockito.verify { + FrameworkStatsLog.write( + ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED), + ArgumentMatchers.anyBoolean(), + ArgumentMatchers.eq(keyboardDevice.vendorId), + ArgumentMatchers.eq(keyboardDevice.productId), + ArgumentMatchers.eq(createByteArray( + KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG, + LAYOUT_TYPE_DEFAULT, + "German", + KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD, + "de-Latn", + LAYOUT_TYPE_QWERTZ)) + ) + } + } + } + + @Test + fun testConfigurationLogged_onInputDeviceAdded_DeviceBasedSelection() { + val imeInfos = listOf( + KeyboardLayoutManager.ImeInfo(0, imeInfo, + createImeSubtypeForLanguageTagAndLayoutType("de-Latn", "qwertz"))) + Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping + NewSettingsApiFlag(true).use { + keyboardLayoutManager.onInputDeviceAdded(englishQwertyKeyboardDevice.id) + ExtendedMockito.verify { + FrameworkStatsLog.write( + ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED), + ArgumentMatchers.anyBoolean(), + ArgumentMatchers.eq(englishQwertyKeyboardDevice.vendorId), + ArgumentMatchers.eq(englishQwertyKeyboardDevice.productId), + ArgumentMatchers.eq(createByteArray( + "en", + LAYOUT_TYPE_QWERTY, + "English (US)", + KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE, + "de-Latn", + LAYOUT_TYPE_QWERTZ)) + ) + } + } + } + + @Test + fun testConfigurationLogged_onInputDeviceAdded_DefaultSelection() { + val imeInfos = listOf(KeyboardLayoutManager.ImeInfo(0, imeInfo, createImeSubtype())) + Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping + NewSettingsApiFlag(true).use { + keyboardLayoutManager.onInputDeviceAdded(keyboardDevice.id) + ExtendedMockito.verify { + FrameworkStatsLog.write( + ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED), + ArgumentMatchers.anyBoolean(), + ArgumentMatchers.eq(keyboardDevice.vendorId), + ArgumentMatchers.eq(keyboardDevice.productId), + ArgumentMatchers.eq(createByteArray( + KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG, + LAYOUT_TYPE_DEFAULT, + "Default", + KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEFAULT, + KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG, + LAYOUT_TYPE_DEFAULT)) + ) + } + } + } + + @Test + fun testConfigurationNotLogged_onInputDeviceChanged() { + val imeInfos = listOf(KeyboardLayoutManager.ImeInfo(0, imeInfo, createImeSubtype())) + Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping + NewSettingsApiFlag(true).use { + keyboardLayoutManager.onInputDeviceChanged(keyboardDevice.id) + ExtendedMockito.verify({ + FrameworkStatsLog.write( + ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED), + ArgumentMatchers.anyBoolean(), + ArgumentMatchers.anyInt(), + ArgumentMatchers.anyInt(), + ArgumentMatchers.any(ByteArray::class.java) + ) + }, Mockito.times(0)) + } + } + private fun assertCorrectLayout( device: InputDevice, imeSubtype: InputMethodSubtype, @@ -842,18 +948,60 @@ class KeyboardLayoutManagerTests { } private fun createImeSubtype(): InputMethodSubtype = - InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(nextImeSubtypeId++).build() + createImeSubtypeForLanguageTagAndLayoutType(null, null) private fun createImeSubtypeForLanguageTag(languageTag: String): InputMethodSubtype = - InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(nextImeSubtypeId++) - .setLanguageTag(languageTag).build() + createImeSubtypeForLanguageTagAndLayoutType(languageTag, null) private fun createImeSubtypeForLanguageTagAndLayoutType( - languageTag: String, - layoutType: String - ): InputMethodSubtype = - InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(nextImeSubtypeId++) - .setPhysicalKeyboardHint(ULocale.forLanguageTag(languageTag), layoutType).build() + languageTag: String?, + layoutType: String? + ): InputMethodSubtype { + val builder = InputMethodSubtype.InputMethodSubtypeBuilder() + .setSubtypeId(nextImeSubtypeId++) + .setIsAuxiliary(false) + .setSubtypeMode("keyboard") + if (languageTag != null && layoutType != null) { + builder.setPhysicalKeyboardHint(ULocale.forLanguageTag(languageTag), layoutType) + } else if (languageTag != null) { + builder.setLanguageTag(languageTag) + } + return builder.build() + } + + private fun createByteArray( + expectedLanguageTag: String, expectedLayoutType: Int, expectedLayoutName: String, + expectedCriteria: Int, expectedImeLanguageTag: String, expectedImeLayoutType: Int): ByteArray { + val proto = ProtoOutputStream() + val keyboardLayoutConfigToken = proto.start( + KeyboardConfiguredProto.RepeatedKeyboardLayoutConfig.KEYBOARD_LAYOUT_CONFIG) + proto.write( + KeyboardConfiguredProto.KeyboardLayoutConfig.KEYBOARD_LANGUAGE_TAG, + expectedLanguageTag + ) + proto.write( + KeyboardConfiguredProto.KeyboardLayoutConfig.KEYBOARD_LAYOUT_TYPE, + expectedLayoutType + ) + proto.write( + KeyboardConfiguredProto.KeyboardLayoutConfig.KEYBOARD_LAYOUT_NAME, + expectedLayoutName + ) + proto.write( + KeyboardConfiguredProto.KeyboardLayoutConfig.LAYOUT_SELECTION_CRITERIA, + expectedCriteria + ) + proto.write( + KeyboardConfiguredProto.KeyboardLayoutConfig.IME_LANGUAGE_TAG, + expectedImeLanguageTag + ) + proto.write( + KeyboardConfiguredProto.KeyboardLayoutConfig.IME_LAYOUT_TYPE, + expectedImeLayoutType + ) + proto.end(keyboardLayoutConfigToken); + return proto.bytes + } private fun hasLayout(layoutList: Array<KeyboardLayout>, layoutDesc: String): Boolean { for (kl in layoutList) { diff --git a/tests/InputMethodStressTest/Android.bp b/tests/InputMethodStressTest/Android.bp index 84845c69fb27..58ceb3f3edf4 100644 --- a/tests/InputMethodStressTest/Android.bp +++ b/tests/InputMethodStressTest/Android.bp @@ -26,7 +26,7 @@ android_test { "compatibility-device-util-axt", "platform-test-annotations", "platform-test-rules", - "truth-prebuilt", + "truth", ], test_suites: [ "general-tests", diff --git a/tests/InputScreenshotTest/Android.bp b/tests/InputScreenshotTest/Android.bp index eee486f99748..15aaa463cce7 100644 --- a/tests/InputScreenshotTest/Android.bp +++ b/tests/InputScreenshotTest/Android.bp @@ -29,7 +29,7 @@ android_test { "androidx.lifecycle_lifecycle-livedata-ktx", "androidx.lifecycle_lifecycle-runtime-compose", "androidx.navigation_navigation-compose", - "truth-prebuilt", + "truth", "androidx.compose.runtime_runtime", "androidx.test.core", "androidx.test.ext.junit", @@ -47,7 +47,7 @@ android_test { "services.core.unboosted", "testables", "testng", - "truth-prebuilt", + "truth", ], libs: [ "android.test.mock", diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp index ef45864dd93b..ddec8fa1d70a 100644 --- a/tests/Internal/Android.bp +++ b/tests/Internal/Android.bp @@ -19,7 +19,7 @@ android_test { "junit", "androidx.test.rules", "mockito-target-minus-junit4", - "truth-prebuilt", + "truth", "platform-test-annotations", ], java_resource_dirs: ["res"], diff --git a/tests/LocalizationTest/Android.bp b/tests/LocalizationTest/Android.bp index 4e0b0a89d972..909ca5972552 100644 --- a/tests/LocalizationTest/Android.bp +++ b/tests/LocalizationTest/Android.bp @@ -34,7 +34,7 @@ android_test { "androidx.test.ext.junit", "androidx.test.rules", "mockito-target-extended-minus-junit4", - "truth-prebuilt", + "truth", ], jni_libs: [ // For mockito extended diff --git a/tests/MidiTests/Android.bp b/tests/MidiTests/Android.bp index 254770d21818..fcacab3fb13c 100644 --- a/tests/MidiTests/Android.bp +++ b/tests/MidiTests/Android.bp @@ -31,7 +31,7 @@ android_test { "mockito-target-inline-minus-junit4", "platform-test-annotations", "services.midi", - "truth-prebuilt", + "truth", ], jni_libs: ["libdexmakerjvmtiagent"], certificate: "platform", diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp index 1e1dc8458560..e0e6c4c43b16 100644 --- a/tests/PackageWatchdog/Android.bp +++ b/tests/PackageWatchdog/Android.bp @@ -32,7 +32,7 @@ android_test { "androidx.test.rules", "services.core", "services.net", - "truth-prebuilt", + "truth", ], libs: ["android.test.runner"], jni_libs: [ diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp index f0f9c4bdd721..fd992cf415cf 100644 --- a/tests/PlatformCompatGating/Android.bp +++ b/tests/PlatformCompatGating/Android.bp @@ -38,7 +38,7 @@ android_test { "androidx.test.ext.junit", "mockito-target-minus-junit4", "testng", - "truth-prebuilt", + "truth", "platform-compat-test-rules", ], } diff --git a/tests/PlatformCompatGating/test-rules/Android.bp b/tests/PlatformCompatGating/test-rules/Android.bp index 5f91f9d0e505..f6a41c2f44b7 100644 --- a/tests/PlatformCompatGating/test-rules/Android.bp +++ b/tests/PlatformCompatGating/test-rules/Android.bp @@ -29,7 +29,7 @@ java_library { static_libs: [ "junit", "androidx.test.core", - "truth-prebuilt", - "core-compat-test-rules" + "truth", + "core-compat-test-rules", ], } diff --git a/tests/SurfaceViewBufferTests/Android.bp b/tests/SurfaceViewBufferTests/Android.bp index 38313f85c31d..055d6258d1ac 100644 --- a/tests/SurfaceViewBufferTests/Android.bp +++ b/tests/SurfaceViewBufferTests/Android.bp @@ -45,7 +45,7 @@ android_test { "kotlinx-coroutines-android", "flickerlib", "flickerlib-trace_processor_shell", - "truth-prebuilt", + "truth", "cts-wm-util", "CtsSurfaceValidatorLib", ], diff --git a/tests/TaskOrganizerTest/Android.bp b/tests/TaskOrganizerTest/Android.bp index bf12f423f145..d2ade34148e2 100644 --- a/tests/TaskOrganizerTest/Android.bp +++ b/tests/TaskOrganizerTest/Android.bp @@ -43,6 +43,6 @@ android_test { "kotlinx-coroutines-android", "flickerlib", "flickerlib-trace_processor_shell", - "truth-prebuilt", + "truth", ], } diff --git a/tests/TelephonyCommonTests/Android.bp b/tests/TelephonyCommonTests/Android.bp index 81ec265c2c29..b968e5d81148 100644 --- a/tests/TelephonyCommonTests/Android.bp +++ b/tests/TelephonyCommonTests/Android.bp @@ -32,11 +32,11 @@ android_test { static_libs: [ "mockito-target-extended", "androidx.test.rules", - "truth-prebuilt", + "truth", "platform-test-annotations", "androidx.core_core", "androidx.fragment_fragment", - "androidx.test.ext.junit" + "androidx.test.ext.junit", ], jni_libs: ["libdexmakerjvmtiagent"], diff --git a/tests/TrustTests/Android.bp b/tests/TrustTests/Android.bp index c216bced81f0..4e75a1d02a41 100644 --- a/tests/TrustTests/Android.bp +++ b/tests/TrustTests/Android.bp @@ -28,7 +28,7 @@ android_test { "flag-junit", "mockito-target-minus-junit4", "servicestests-utils", - "truth-prebuilt", + "truth", ], libs: [ "android.test.runner", diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp index 9bfcc18ee301..ddb3649a8320 100644 --- a/tests/UpdatableSystemFontTest/Android.bp +++ b/tests/UpdatableSystemFontTest/Android.bp @@ -30,7 +30,7 @@ android_test { "androidx.test.uiautomator_uiautomator", "compatibility-device-util-axt", "platform-test-annotations", - "truth-prebuilt", + "truth", ], test_suites: [ "general-tests", diff --git a/tests/UsbManagerTests/Android.bp b/tests/UsbManagerTests/Android.bp index 97fbf5b32035..c02d8e96abb0 100644 --- a/tests/UsbManagerTests/Android.bp +++ b/tests/UsbManagerTests/Android.bp @@ -31,7 +31,7 @@ android_test { "androidx.test.rules", "mockito-target-inline-minus-junit4", "platform-test-annotations", - "truth-prebuilt", + "truth", "UsbManagerTestLib", ], jni_libs: ["libdexmakerjvmtiagent"], diff --git a/tests/UsbManagerTests/lib/Android.bp b/tests/UsbManagerTests/lib/Android.bp index 994484cd63bf..4e5a70fef0ca 100644 --- a/tests/UsbManagerTests/lib/Android.bp +++ b/tests/UsbManagerTests/lib/Android.bp @@ -34,7 +34,7 @@ android_library { "services.core", "services.net", "services.usb", - "truth-prebuilt", + "truth", "androidx.core_core", ], libs: [ diff --git a/tests/UsbTests/Android.bp b/tests/UsbTests/Android.bp index c60c519ec4d4..92c271165ad7 100644 --- a/tests/UsbTests/Android.bp +++ b/tests/UsbTests/Android.bp @@ -34,7 +34,7 @@ android_test { "services.core", "services.net", "services.usb", - "truth-prebuilt", + "truth", "UsbManagerTestLib", ], jni_libs: [ diff --git a/tests/componentalias/Android.bp b/tests/componentalias/Android.bp index 01d34e4ff645..39037f22fdcb 100644 --- a/tests/componentalias/Android.bp +++ b/tests/componentalias/Android.bp @@ -25,7 +25,7 @@ java_defaults { "androidx.test.rules", "compatibility-device-util-axt", "mockito-target-extended-minus-junit4", - "truth-prebuilt", + "truth", ], libs: ["android.test.base"], srcs: [ diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp index 7323b0f4c14f..977b2768e702 100644 --- a/tools/aapt2/Android.bp +++ b/tools/aapt2/Android.bp @@ -220,6 +220,7 @@ genrule { name: "aapt2-protos", tools: [":soong_zip"], srcs: [ + "ApkInfo.proto", "Configuration.proto", "ResourcesInternal.proto", "ResourceMetadata.proto", diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp index 87da09a7b054..8c644cf83339 100644 --- a/tools/aapt2/java/AnnotationProcessor.cpp +++ b/tools/aapt2/java/AnnotationProcessor.cpp @@ -49,16 +49,19 @@ struct AnnotationRule { kDeprecated = 0x01, kSystemApi = 0x02, kTestApi = 0x04, + kFlaggedApi = 0x08, }; StringPiece doc_str; uint32_t bit_mask; StringPiece annotation; + bool preserve_params; }; -static std::array<AnnotationRule, 2> sAnnotationRules = {{ - {"@SystemApi", AnnotationRule::kSystemApi, "@android.annotation.SystemApi"}, - {"@TestApi", AnnotationRule::kTestApi, "@android.annotation.TestApi"}, +static std::array<AnnotationRule, 3> sAnnotationRules = {{ + {"@SystemApi", AnnotationRule::kSystemApi, "@android.annotation.SystemApi", true}, + {"@TestApi", AnnotationRule::kTestApi, "@android.annotation.TestApi", false}, + {"@FlaggedApi", AnnotationRule::kFlaggedApi, "@android.annotation.FlaggedApi", true}, }}; void AnnotationProcessor::AppendCommentLine(std::string comment) { @@ -73,12 +76,11 @@ void AnnotationProcessor::AppendCommentLine(std::string comment) { std::string::size_type idx = comment.find(rule.doc_str.data()); if (idx != std::string::npos) { // Captures all parameters associated with the specified annotation rule - // by matching the first pair of parantheses after the rule. - std::regex re(std::string(rule.doc_str) += "\\s*\\((.+)\\)"); + // by matching the first pair of parentheses after the rule. + std::regex re(std::string(rule.doc_str).append(R"(\s*\((.+)\))")); std::smatch match_result; const bool is_match = std::regex_search(comment, match_result, re); - // We currently only capture and preserve parameters for SystemApi. - if (is_match && rule.bit_mask == AnnotationRule::kSystemApi) { + if (is_match && rule.preserve_params) { annotation_parameter_map_[rule.bit_mask] = match_result[1].str(); comment.erase(comment.begin() + match_result.position(), comment.begin() + match_result.position() + match_result.length()); diff --git a/tools/aapt2/java/AnnotationProcessor_test.cpp b/tools/aapt2/java/AnnotationProcessor_test.cpp index 6bc8902a6dcf..e98e96ba3bc3 100644 --- a/tools/aapt2/java/AnnotationProcessor_test.cpp +++ b/tools/aapt2/java/AnnotationProcessor_test.cpp @@ -76,6 +76,36 @@ TEST(AnnotationProcessorTest, EmitsSystemApiAnnotationParamsAndRemovesFromCommen EXPECT_THAT(annotations, HasSubstr("This is a system API")); } +TEST(AnnotationProcessorTest, EmitsFlaggedApiAnnotationAndRemovesFromComment) { + AnnotationProcessor processor; + processor.AppendComment("@FlaggedApi This is a flagged API"); + + std::string annotations; + StringOutputStream out(&annotations); + Printer printer(&out); + processor.Print(&printer); + out.Flush(); + + EXPECT_THAT(annotations, HasSubstr("@android.annotation.FlaggedApi")); + EXPECT_THAT(annotations, Not(HasSubstr("@FlaggedApi"))); + EXPECT_THAT(annotations, HasSubstr("This is a flagged API")); +} + +TEST(AnnotationProcessorTest, EmitsFlaggedApiAnnotationParamsAndRemovesFromComment) { + AnnotationProcessor processor; + processor.AppendComment("@FlaggedApi (\"android.flags.my_flag\") This is a flagged API"); + + std::string annotations; + StringOutputStream out(&annotations); + Printer printer(&out); + processor.Print(&printer); + out.Flush(); + + EXPECT_THAT(annotations, HasSubstr("@android.annotation.FlaggedApi(\"android.flags.my_flag\")")); + EXPECT_THAT(annotations, Not(HasSubstr("@FlaggedApi"))); + EXPECT_THAT(annotations, HasSubstr("This is a flagged API")); +} + TEST(AnnotationProcessorTest, EmitsTestApiAnnotationAndRemovesFromComment) { AnnotationProcessor processor; processor.AppendComment("@TestApi This is a test API"); diff --git a/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp index e7fb2debfc4e..b71e5c47c70e 100644 --- a/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp +++ b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp @@ -24,7 +24,7 @@ java_library_host { ], static_libs: [ "junit", - "truth-prebuilt", + "truth", "mockito", // http://cs/h/googleplex-android/platform/superproject/main/+/main:platform_testing/libraries/annotations/src/android/platform/test/annotations/ diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp index 05d6a43cdb0f..f9dc305a4e3e 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp @@ -104,7 +104,7 @@ java_library_host { ], static_libs: [ "junit", - "truth-prebuilt", + "truth", // http://cs/h/googleplex-android/platform/superproject/main/+/main:platform_testing/libraries/annotations/src/android/platform/test/annotations/ "platform-test-annotations", diff --git a/tools/processors/immutability/Android.bp b/tools/processors/immutability/Android.bp index a7d69039fcb0..ecc283b0b37e 100644 --- a/tools/processors/immutability/Android.bp +++ b/tools/processors/immutability/Android.bp @@ -50,7 +50,7 @@ java_test_host { static_libs: [ "compile-testing-prebuilt", - "truth-prebuilt", + "truth", "junit", "kotlin-reflect", "ImmutabilityAnnotationProcessorHostLibrary", diff --git a/tools/processors/intdef_mappings/Android.bp b/tools/processors/intdef_mappings/Android.bp index 7059c52ddc76..9c755b7d58c2 100644 --- a/tools/processors/intdef_mappings/Android.bp +++ b/tools/processors/intdef_mappings/Android.bp @@ -38,7 +38,7 @@ java_test_host { static_libs: [ "compile-testing-prebuilt", - "truth-prebuilt", + "truth", "junit", "guava", "libintdef-annotation-processor", diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp index 7a299694741a..5a0f742372d7 100644 --- a/wifi/tests/Android.bp +++ b/wifi/tests/Android.bp @@ -40,7 +40,7 @@ android_test { "frameworks-base-testutils", "guava", "mockito-target-minus-junit4", - "truth-prebuilt", + "truth", ], libs: [ |